mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
Refcounter for asset manager and gl resources disposal for webcomponent.
This commit is contained in:
parent
8380540c99
commit
f4e375a2cd
@ -36,6 +36,7 @@ export class AssetManagerBase implements Disposable {
|
|||||||
private textureLoader: (image: HTMLImageElement | ImageBitmap) => Texture;
|
private textureLoader: (image: HTMLImageElement | ImageBitmap) => Texture;
|
||||||
private downloader: Downloader;
|
private downloader: Downloader;
|
||||||
private assets: StringMap<any> = {};
|
private assets: StringMap<any> = {};
|
||||||
|
private assetsRefCount: StringMap<number> = {};
|
||||||
private assetsLoaded: StringMap<Promise<any>> = {};
|
private assetsLoaded: StringMap<Promise<any>> = {};
|
||||||
private errors: StringMap<string> = {};
|
private errors: StringMap<string> = {};
|
||||||
private toLoad = 0;
|
private toLoad = 0;
|
||||||
@ -56,6 +57,7 @@ export class AssetManagerBase implements Disposable {
|
|||||||
this.toLoad--;
|
this.toLoad--;
|
||||||
this.loaded++;
|
this.loaded++;
|
||||||
this.assets[path] = asset;
|
this.assets[path] = asset;
|
||||||
|
this.assetsRefCount[path] = (this.assetsRefCount[path] || 0) + 1;
|
||||||
if (callback) callback(path, asset);
|
if (callback) callback(path, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,15 +334,16 @@ export class AssetManagerBase implements Disposable {
|
|||||||
remove (path: string) {
|
remove (path: string) {
|
||||||
path = this.pathPrefix + path;
|
path = this.pathPrefix + path;
|
||||||
let asset = this.assets[path];
|
let asset = this.assets[path];
|
||||||
if ((<any>asset).dispose) (<any>asset).dispose();
|
if (asset.dispose) asset.dispose();
|
||||||
delete this.assets[path];
|
delete this.assets[path];
|
||||||
|
delete this.assetsRefCount[path];
|
||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAll () {
|
removeAll () {
|
||||||
for (let key in this.assets) {
|
for (let path in this.assets) {
|
||||||
let asset = this.assets[key];
|
let asset = this.assets[path];
|
||||||
if ((<any>asset).dispose) (<any>asset).dispose();
|
if (asset.dispose) asset.dispose();
|
||||||
}
|
}
|
||||||
this.assets = {};
|
this.assets = {};
|
||||||
}
|
}
|
||||||
@ -361,6 +364,14 @@ export class AssetManagerBase implements Disposable {
|
|||||||
this.removeAll();
|
this.removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispose asset only if it's not used by others
|
||||||
|
disposeAsset(path: string, a?: string) {
|
||||||
|
if (--this.assetsRefCount[path] === 0) {
|
||||||
|
const asset = this.assets[path];
|
||||||
|
if (asset.dispose) asset.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hasErrors () {
|
hasErrors () {
|
||||||
return Object.keys(this.errors).length > 0;
|
return Object.keys(this.errors).length > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const boi = spine.getSpineWidget("boi");
|
const boi = spine.getSpineWidget("boi");
|
||||||
let { skeleton } = await boi.loadingPromise;
|
let { skeleton } = await boi.whenReady;
|
||||||
|
|
||||||
const animations = skeleton.data.animations.map(({ name }) => name);
|
const animations = skeleton.data.animations.map(({ name }) => name);
|
||||||
animations.push("none");
|
animations.push("none");
|
||||||
@ -119,7 +119,7 @@
|
|||||||
boi.skeletonPath = skeletonPath;
|
boi.skeletonPath = skeletonPath;
|
||||||
boi.start();
|
boi.start();
|
||||||
|
|
||||||
await boi.loadingPromise;
|
await boi.whenReady;
|
||||||
skeleton = boi.skeleton;
|
skeleton = boi.skeleton;
|
||||||
|
|
||||||
refillAnimations();
|
refillAnimations();
|
||||||
|
|||||||
@ -584,7 +584,7 @@
|
|||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = spine.getSpineWidget("raptor");
|
const widget = spine.getSpineWidget("raptor");
|
||||||
const { state } = await widget.loadingPromise;
|
const { state } = await widget.whenReady;
|
||||||
let isRoaring = false;
|
let isRoaring = false;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const newAnimation = isRoaring ? "walk" : "roar";
|
const newAnimation = isRoaring ? "walk" : "roar";
|
||||||
@ -611,7 +611,7 @@
|
|||||||
// using js, access the skeleton and the state asynchronously
|
// using js, access the skeleton and the state asynchronously
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = spine.getSpineWidget("raptor");
|
const widget = spine.getSpineWidget("raptor");
|
||||||
const { state } = await widget.loadingPromise;
|
const { state } = await widget.whenReady;
|
||||||
let isRoaring = false;
|
let isRoaring = false;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const newAnimation = isRoaring ? "walk" : "roar";
|
const newAnimation = isRoaring ? "walk" : "roar";
|
||||||
@ -672,7 +672,7 @@
|
|||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
const widget = await spine.getSpineWidget("spineboy-change-animation").loadingPromise;
|
const widget = await spine.getSpineWidget("spineboy-change-animation").whenReady;
|
||||||
let toogleAnimation = false;
|
let toogleAnimation = false;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const newAnimation = toogleAnimation ? "jump" : "death";
|
const newAnimation = toogleAnimation ? "jump" : "death";
|
||||||
@ -682,7 +682,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const widget = await spine.getSpineWidget("spineboy-change-animation2").loadingPromise;
|
const widget = await spine.getSpineWidget("spineboy-change-animation2").whenReady;
|
||||||
let toogleAnimation = false;
|
let toogleAnimation = false;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const newAnimation = toogleAnimation ? "jump" : "death";
|
const newAnimation = toogleAnimation ? "jump" : "death";
|
||||||
@ -886,7 +886,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function updateCelesteAnimations() {
|
async function updateCelesteAnimations() {
|
||||||
const celesteAnimations = await spine.getSpineWidget("celeste-animations").loadingPromise;
|
const celesteAnimations = await spine.getSpineWidget("celeste-animations").whenReady;
|
||||||
var celesteAnimationsTextArea = document.getElementById("celeste-animations-text-area");
|
var celesteAnimationsTextArea = document.getElementById("celeste-animations-text-area");
|
||||||
celesteAnimations.setAttribute("animations", celesteAnimationsTextArea.value)
|
celesteAnimations.setAttribute("animations", celesteAnimationsTextArea.value)
|
||||||
}
|
}
|
||||||
@ -909,7 +909,7 @@
|
|||||||
// using js, access the skeleton and the state asynchronously
|
// using js, access the skeleton and the state asynchronously
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = spine.getSpineWidget("raptor");
|
const widget = spine.getSpineWidget("raptor");
|
||||||
const { state } = await widget.loadingPromise;
|
const { state } = await widget.whenReady;
|
||||||
let isRoaring = false;
|
let isRoaring = false;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const newAnimation = isRoaring ? "walk" : "roar";
|
const newAnimation = isRoaring ? "walk" : "roar";
|
||||||
@ -978,6 +978,101 @@
|
|||||||
/////////////////////
|
/////////////////////
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
/////////////////////
|
||||||
|
// start section //
|
||||||
|
/////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="section vertical-split">
|
||||||
|
|
||||||
|
<div class="split-top split">
|
||||||
|
<div class="split-left">
|
||||||
|
<button id="add-delete" onclick="addDiv()" disabled>Add</button>
|
||||||
|
<button onclick="removeDiv()">Remove</button>
|
||||||
|
</div>
|
||||||
|
<div class="split-right">
|
||||||
|
<div id="container-delete" style="display: flex; height: 300px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const containerDelete = document.getElementById('container-delete');
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
document.getElementById('add-delete').removeAttribute("disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function addDiv() {
|
||||||
|
const skins = [
|
||||||
|
"Assassin", "Beardy", "Buck",
|
||||||
|
"Chuck", "Commander", "Ducky", "Dummy",
|
||||||
|
"Fletch", "Gabriel", "MetalMan", "Pamela-1",
|
||||||
|
"Pamela-2", "Pamela-3", "Pamela-4", "Pamela-5",
|
||||||
|
"Stumpy", "Truck", "Turbo", "Young",
|
||||||
|
];
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const randomIndex = Math.floor(Math.random() * skins.length);
|
||||||
|
const skin = skins[randomIndex];
|
||||||
|
console.log(randomIndex, skin);
|
||||||
|
div.style.flex = "1";
|
||||||
|
div.style.margin = "1px";
|
||||||
|
div.style.backgroundColor = "lightblue";
|
||||||
|
div.style.flex = "1";
|
||||||
|
div.innerHTML = `
|
||||||
|
<spine-widget
|
||||||
|
atlas="assets/spineboy-pma.atlas"
|
||||||
|
skeleton="assets/spineboy-pro.skel"
|
||||||
|
animation="walk"
|
||||||
|
></spine-widget>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// div.innerHTML = `
|
||||||
|
// <spine-widget
|
||||||
|
// atlas="../demos/assets/heroes.atlas"
|
||||||
|
// skeleton="../demos/assets/demos.json"
|
||||||
|
// json-skeleton-key="heroes"
|
||||||
|
// animation="floorIdle"
|
||||||
|
// skin="${skin}"
|
||||||
|
// isdraggable
|
||||||
|
// ></spine-widget>
|
||||||
|
// `;
|
||||||
|
|
||||||
|
containerDelete.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDiv() {
|
||||||
|
if (containerDelete.lastChild) {
|
||||||
|
containerDelete.removeChild(containerDelete.lastChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="split-bottom">
|
||||||
|
<pre><code id="code-display">
|
||||||
|
<script>escapeHTMLandInject(`
|
||||||
|
<spine-widget
|
||||||
|
atlas="assets/sack-pma.atlas"
|
||||||
|
skeleton="assets/sack-pro.skel"
|
||||||
|
animation="cape-follow-example"
|
||||||
|
debug
|
||||||
|
></spine-widget>`
|
||||||
|
);</script>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
/////////////////////
|
||||||
|
// end section //
|
||||||
|
/////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// start section //
|
// start section //
|
||||||
@ -1109,7 +1204,7 @@
|
|||||||
const widget = spine.getSpineWidget("widget-loading");
|
const widget = spine.getSpineWidget("widget-loading");
|
||||||
async function reloadWidget(element) {
|
async function reloadWidget(element) {
|
||||||
element.disabled = true;
|
element.disabled = true;
|
||||||
await widget.loadingPromise;
|
await widget.whenReady;
|
||||||
const skeleton = widget.skeleton;
|
const skeleton = widget.skeleton;
|
||||||
widget.loading = true;
|
widget.loading = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -1663,7 +1758,7 @@
|
|||||||
<br>
|
<br>
|
||||||
By default, assets are loaded immeaditely. You can postpone that by setting <code>manual-start="false"</code>.
|
By default, assets are loaded immeaditely. You can postpone that by setting <code>manual-start="false"</code>.
|
||||||
Then add the widget to the dom using the asynchronous method <code>appendTo</code>. It's your responsibility to call <code>start()</code> on the widget.
|
Then add the widget to the dom using the asynchronous method <code>appendTo</code>. It's your responsibility to call <code>start()</code> on the widget.
|
||||||
As usual, just wait on the <code>loadingPromise</code> to act on the <code>skeleton</code> or the <code>state</code>.
|
As usual, just wait on the <code>whenReady</code> to act on the <code>skeleton</code> or the <code>state</code>.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -1701,7 +1796,7 @@
|
|||||||
|
|
||||||
// access the state of the first widget and change the animation
|
// access the state of the first widget and change the animation
|
||||||
if (i === 0 && j === 0) {
|
if (i === 0 && j === 0) {
|
||||||
await widgetSection.loadingPromise;
|
await widgetSection.whenReady;
|
||||||
widgetSection.state.setAnimation(0, "emotes/angry", true);
|
widgetSection.state.setAnimation(0, "emotes/angry", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1749,7 +1844,7 @@ skins.forEach((skin, i) => {
|
|||||||
|
|
||||||
// access the state of the first widget and change the animation
|
// access the state of the first widget and change the animation
|
||||||
if (i === 0 && j === 0) {
|
if (i === 0 && j === 0) {
|
||||||
await widgetSection.loadingPromise;
|
await widgetSection.whenReady;
|
||||||
widgetSection.state.setAnimation(0, "emotes/angry", true);
|
widgetSection.state.setAnimation(0, "emotes/angry", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1813,7 +1908,7 @@ skins.forEach((skin, i) => {
|
|||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const coinWidget = spine.getSpineWidget("coin");
|
const coinWidget = spine.getSpineWidget("coin");
|
||||||
await coinWidget.loadingPromise;
|
await coinWidget.whenReady;
|
||||||
|
|
||||||
let raptorWalking = true;
|
let raptorWalking = true;
|
||||||
coinWidget.onScreenFunction = widget => {
|
coinWidget.onScreenFunction = widget => {
|
||||||
@ -1843,7 +1938,7 @@ skins.forEach((skin, i) => {
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const coinWidget = spine.getSpineWidget("coin");
|
const coinWidget = spine.getSpineWidget("coin");
|
||||||
await coinWidget.loadingPromise;
|
await coinWidget.whenReady;
|
||||||
|
|
||||||
let raptorWalking = true;
|
let raptorWalking = true;
|
||||||
coinWidget.onScreenFunction = widget => {
|
coinWidget.onScreenFunction = widget => {
|
||||||
@ -1913,7 +2008,7 @@ skins.forEach((skin, i) => {
|
|||||||
}
|
}
|
||||||
if (!dragon.pages.includes(pageIndex)) {
|
if (!dragon.pages.includes(pageIndex)) {
|
||||||
dragon.pages.push(pageIndex);
|
dragon.pages.push(pageIndex);
|
||||||
dragon.loadTexturesInPagesAttribute(dragon.textureAtlas);
|
dragon.loadTexturesInPagesAttribute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -1945,7 +2040,7 @@ function loadPageDragon(pageIndex) {
|
|||||||
}
|
}
|
||||||
if (!dragon.pages.includes(pageIndex)) {
|
if (!dragon.pages.includes(pageIndex)) {
|
||||||
dragon.pages.push(pageIndex);
|
dragon.pages.push(pageIndex);
|
||||||
dragon.loadTexturesInPagesAttribute(dragon.textureAtlas);
|
dragon.loadTexturesInPagesAttribute();
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
</script>
|
</script>
|
||||||
@ -2102,7 +2197,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const tank = spine.getSpineWidget("tank");
|
const tank = spine.getSpineWidget("tank");
|
||||||
const tank2 = spine.getSpineWidget("tank2");
|
const tank2 = spine.getSpineWidget("tank2");
|
||||||
await Promise.all([tank.loadingPromise, tank2.loadingPromise]);
|
await Promise.all([tank.whenReady, tank2.whenReady]);
|
||||||
|
|
||||||
tank.beforeUpdateWorldTransforms = (skeleton, state) => {
|
tank.beforeUpdateWorldTransforms = (skeleton, state) => {
|
||||||
if (!tank.onScreen) return;
|
if (!tank.onScreen) return;
|
||||||
@ -2143,7 +2238,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const tank = spine.getSpineWidget("tank");
|
const tank = spine.getSpineWidget("tank");
|
||||||
const tank2 = spine.getSpineWidget("tank2");
|
const tank2 = spine.getSpineWidget("tank2");
|
||||||
await Promise.all([tank.loadingPromise, tank2.loadingPromise]);
|
await Promise.all([tank.whenReady, tank2.whenReady]);
|
||||||
|
|
||||||
// since we want the tank to overflow the div, we set fit to none
|
// since we want the tank to overflow the div, we set fit to none
|
||||||
// then we "sync" the tank scale to the one of the tank above
|
// then we "sync" the tank scale to the one of the tank above
|
||||||
@ -2230,7 +2325,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
|||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const celeste = spine.getSpineWidget("celeste");
|
const celeste = spine.getSpineWidget("celeste");
|
||||||
await celeste.loadingPromise;
|
await celeste.whenReady;
|
||||||
celeste.state.setAnimation(0, "swing", true);
|
celeste.state.setAnimation(0, "swing", true);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
@ -2299,7 +2394,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const celeste = spine.getSpineWidget("celeste");
|
const celeste = spine.getSpineWidget("celeste");
|
||||||
await celeste.loadingPromise;
|
await celeste.whenReady;
|
||||||
celeste.state.setAnimation(0, "swing", true);
|
celeste.state.setAnimation(0, "swing", true);
|
||||||
})();`);
|
})();`);
|
||||||
</script>
|
</script>
|
||||||
@ -2725,7 +2820,7 @@ function createCircleOfDivs(numDivs = 8) {
|
|||||||
|
|
||||||
customElements.whenDefined('spine-widget').then(async () => {
|
customElements.whenDefined('spine-widget').then(async () => {
|
||||||
const widget = spine.getSpineWidget(\`owl\${i}\`);
|
const widget = spine.getSpineWidget(\`owl\${i}\`);
|
||||||
await widget.loadingPromise;
|
await widget.whenReady;
|
||||||
widget.state.setAnimation(1, "blink", true);
|
widget.state.setAnimation(1, "blink", true);
|
||||||
|
|
||||||
const control = widget.skeleton.findBone("control");
|
const control = widget.skeleton.findBone("control");
|
||||||
@ -2821,7 +2916,7 @@ function createCircleOfDivs(numDivs = 8) {
|
|||||||
|
|
||||||
customElements.whenDefined('spine-widget').then(async () => {
|
customElements.whenDefined('spine-widget').then(async () => {
|
||||||
const widget = spine.getSpineWidget(`owl${i}`);
|
const widget = spine.getSpineWidget(`owl${i}`);
|
||||||
await widget.loadingPromise;
|
await widget.whenReady;
|
||||||
widget.state.setAnimation(1, "blink", true);
|
widget.state.setAnimation(1, "blink", true);
|
||||||
|
|
||||||
const control = widget.skeleton.findBone("control");
|
const control = widget.skeleton.findBone("control");
|
||||||
@ -2935,7 +3030,7 @@ const colorPicker = document.getElementById("color-picker");
|
|||||||
const darkPicker = document.getElementById("dark-picker");
|
const darkPicker = document.getElementById("dark-picker");
|
||||||
|
|
||||||
[0, 1].forEach(async (i) => {
|
[0, 1].forEach(async (i) => {
|
||||||
const widget = await spine.getSpineWidget(`interactive${i}`).loadingPromise;
|
const widget = await spine.getSpineWidget(`interactive${i}`).whenReady;
|
||||||
|
|
||||||
widget.cursorEventCallback = (event) => {
|
widget.cursorEventCallback = (event) => {
|
||||||
if (event === "enter") widget.state.setAnimation(0, "emotes/hooray", true).mixDuration = .15;
|
if (event === "enter") widget.state.setAnimation(0, "emotes/hooray", true).mixDuration = .15;
|
||||||
@ -2978,7 +3073,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
></spine-widget>
|
></spine-widget>
|
||||||
|
|
||||||
[0, 1].forEach(async (i) => {
|
[0, 1].forEach(async (i) => {
|
||||||
const widget = await spine.getSpineWidget(\`interactive\${i}\`).loadingPromise;
|
const widget = await spine.getSpineWidget(\`interactive\${i}\`).whenReady;
|
||||||
|
|
||||||
widget.cursorEventCallback = (event) => {
|
widget.cursorEventCallback = (event) => {
|
||||||
if (event === "enter") widget.state.setAnimation(0, "emotes/hooray", true).mixDuration = .15;
|
if (event === "enter") widget.state.setAnimation(0, "emotes/hooray", true).mixDuration = .15;
|
||||||
@ -3055,7 +3150,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = await spine.getSpineWidget("potty").loadingPromise;
|
const widget = await spine.getSpineWidget("potty").whenReady;
|
||||||
widget.followSlot("rain/rain-color", document.getElementById("rain/rain-color"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-color", document.getElementById("rain/rain-color"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-white", document.getElementById("rain/rain-white"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-white", document.getElementById("rain/rain-white"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-blue", document.getElementById("rain/rain-blue"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-blue", document.getElementById("rain/rain-blue"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
@ -3082,7 +3177,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
...
|
...
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = await spine.getSpineWidget("potty").loadingPromise;
|
const widget = await spine.getSpineWidget("potty").whenReady;
|
||||||
widget.followSlot("rain/rain-color", document.getElementById("rain/rain-color"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-color", document.getElementById("rain/rain-color"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-white", document.getElementById("rain/rain-white"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-white", document.getElementById("rain/rain-white"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-blue", document.getElementById("rain/rain-blue"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-blue", document.getElementById("rain/rain-blue"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
@ -3129,7 +3224,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = await spine.getSpineWidget("potty2").loadingPromise;
|
const widget = await spine.getSpineWidget("potty2").whenReady;
|
||||||
widget.followSlot("rain/rain-color", spine.getSpineWidget("potty2-1"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-color", spine.getSpineWidget("potty2-1"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-white", spine.getSpineWidget("potty2-2"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-white", spine.getSpineWidget("potty2-2"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-blue", spine.getSpineWidget("potty2-3"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-blue", spine.getSpineWidget("potty2-3"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
@ -3156,7 +3251,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
...
|
...
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const widget = await spine.getSpineWidget("potty2").loadingPromise;
|
const widget = await spine.getSpineWidget("potty2").whenReady;
|
||||||
widget.followSlot("rain/rain-color", spine.getSpineWidget("potty2-1"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-color", spine.getSpineWidget("potty2-1"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-white", spine.getSpineWidget("potty2-2"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-white", spine.getSpineWidget("potty2-2"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
widget.followSlot("rain/rain-blue", spine.getSpineWidget("potty2-3"), { followAttachmentAttach: false, hideAttachment: true });
|
widget.followSlot("rain/rain-blue", spine.getSpineWidget("potty2-3"), { followAttachmentAttach: false, hideAttachment: true });
|
||||||
@ -3271,7 +3366,7 @@ const darkPicker = document.getElementById("dark-picker");
|
|||||||
div5.style.fontSize = "0.9rem";
|
div5.style.fontSize = "0.9rem";
|
||||||
div5.style.color = "#666";
|
div5.style.color = "#666";
|
||||||
|
|
||||||
await widget.loadingPromise;
|
await widget.whenReady;
|
||||||
|
|
||||||
const emotes = widget.skeleton.data.animations.reduce((acc, { name }) => name.startsWith("emotes") ? [...acc, name] : acc, []);
|
const emotes = widget.skeleton.data.animations.reduce((acc, { name }) => name.startsWith("emotes") ? [...acc, name] : acc, []);
|
||||||
let leaveAnimation = "emotes/wave";
|
let leaveAnimation = "emotes/wave";
|
||||||
@ -3394,7 +3489,7 @@ TODO`
|
|||||||
|
|
||||||
const form = document.getElementById('loginForm');
|
const form = document.getElementById('loginForm');
|
||||||
const widgetButton = spine.getSpineWidget("button-login");
|
const widgetButton = spine.getSpineWidget("button-login");
|
||||||
await widgetButton.loadingPromise;
|
await widgetButton.whenReady;
|
||||||
|
|
||||||
widgetButton.skeleton.color.set(.85, .85, .85, 1);
|
widgetButton.skeleton.color.set(.85, .85, .85, 1);
|
||||||
widgetButton.cursorEventCallback = (event, originalEvent) => {
|
widgetButton.cursorEventCallback = (event, originalEvent) => {
|
||||||
@ -3432,7 +3527,7 @@ TODO`
|
|||||||
widgetButton.followSlot("CLICK ME", divText, { followScale: false });
|
widgetButton.followSlot("CLICK ME", divText, { followScale: false });
|
||||||
|
|
||||||
const widget = spine.getSpineWidget("spineboy-login");
|
const widget = spine.getSpineWidget("spineboy-login");
|
||||||
await widget.loadingPromise;
|
await widget.whenReady;
|
||||||
|
|
||||||
// default settings
|
// default settings
|
||||||
widget.state.data.defaultMix = 0.15;
|
widget.state.data.defaultMix = 0.15;
|
||||||
@ -3987,7 +4082,7 @@ TODO`
|
|||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
/* SECTION 1 */
|
/* SECTION 1 */
|
||||||
const widget1 = await spine.getSpineWidget("list").loadingPromise;
|
const widget1 = await spine.getSpineWidget("list").whenReady;
|
||||||
|
|
||||||
const setInteractionSectionOne = (itemName, trackNumber) => {
|
const setInteractionSectionOne = (itemName, trackNumber) => {
|
||||||
const divName = `${itemName}Div`;
|
const divName = `${itemName}Div`;
|
||||||
@ -4077,7 +4172,7 @@ TODO`
|
|||||||
/* SECTION 2 */
|
/* SECTION 2 */
|
||||||
const btnNext2 = document.getElementById("btn-next-2");
|
const btnNext2 = document.getElementById("btn-next-2");
|
||||||
|
|
||||||
const widget2 = await spine.getSpineWidget("pan").loadingPromise;
|
const widget2 = await spine.getSpineWidget("pan").whenReady;
|
||||||
const foodPiece1 = widget2.skeleton.findSlot(`food-piece-1`);
|
const foodPiece1 = widget2.skeleton.findSlot(`food-piece-1`);
|
||||||
const foodPiece2 = widget2.skeleton.findSlot(`food-piece-2`);
|
const foodPiece2 = widget2.skeleton.findSlot(`food-piece-2`);
|
||||||
const foodPiece3 = widget2.skeleton.findSlot(`food-piece-3`);
|
const foodPiece3 = widget2.skeleton.findSlot(`food-piece-3`);
|
||||||
@ -4137,7 +4232,7 @@ TODO`
|
|||||||
/* SECTION 2 */
|
/* SECTION 2 */
|
||||||
|
|
||||||
/* SECTION 3 */
|
/* SECTION 3 */
|
||||||
const widget3 = await spine.getSpineWidget("delivery").loadingPromise;
|
const widget3 = await spine.getSpineWidget("delivery").whenReady;
|
||||||
const btnNext3 = document.getElementById("btn-next-3");
|
const btnNext3 = document.getElementById("btn-next-3");
|
||||||
const box = widget3.skeleton.findSlot("box");
|
const box = widget3.skeleton.findSlot("box");
|
||||||
|
|
||||||
@ -4186,7 +4281,7 @@ TODO`
|
|||||||
|
|
||||||
|
|
||||||
/* SECTION 4 */
|
/* SECTION 4 */
|
||||||
const widget4 = await spine.getSpineWidget("ready").loadingPromise;
|
const widget4 = await spine.getSpineWidget("ready").whenReady;
|
||||||
|
|
||||||
const slot4Bread = widget4.skeleton.findSlot("salad");
|
const slot4Bread = widget4.skeleton.findSlot("salad");
|
||||||
widget4.addCursorSlotEventCallback(slot4Bread, (slot, event) => {
|
widget4.addCursorSlotEventCallback(slot4Bread, (slot, event) => {
|
||||||
@ -4326,7 +4421,7 @@ TODO`
|
|||||||
(async () => {
|
(async () => {
|
||||||
const spineboy = spine.getSpineWidget("spineboy-game");
|
const spineboy = spine.getSpineWidget("spineboy-game");
|
||||||
const windmill = spine.getSpineWidget("windmill-game");
|
const windmill = spine.getSpineWidget("windmill-game");
|
||||||
await Promise.all([spineboy.loadingPromise, windmill.loadingPromise]);
|
await Promise.all([spineboy.whenReady, windmill.whenReady]);
|
||||||
|
|
||||||
spineboy.state.setAnimation(2, "aim", true);
|
spineboy.state.setAnimation(2, "aim", true);
|
||||||
|
|
||||||
|
|||||||
@ -219,7 +219,7 @@ interface WidgetPublicProperties {
|
|||||||
bounds: Rectangle
|
bounds: Rectangle
|
||||||
onScreen: boolean
|
onScreen: boolean
|
||||||
onScreenAtLeastOnce: boolean
|
onScreenAtLeastOnce: boolean
|
||||||
loadingPromise: Promise<SpineWebComponentWidget>
|
whenReady: Promise<SpineWebComponentWidget>
|
||||||
loading: boolean
|
loading: boolean
|
||||||
started: boolean
|
started: boolean
|
||||||
textureAtlas: TextureAtlas
|
textureAtlas: TextureAtlas
|
||||||
@ -681,19 +681,19 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The skeleton hosted by this widget. It's ready once assets are loaded.
|
* The skeleton hosted by this widget. It's ready once assets are loaded.
|
||||||
* Safely acces this property by using {@link loadingPromise}.
|
* Safely acces this property by using {@link whenReady}.
|
||||||
*/
|
*/
|
||||||
public skeleton?: Skeleton;
|
public skeleton?: Skeleton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The animation state hosted by this widget. It's ready once assets are loaded.
|
* The animation state hosted by this widget. It's ready once assets are loaded.
|
||||||
* Safely acces this property by using {@link loadingPromise}.
|
* Safely acces this property by using {@link whenReady}.
|
||||||
*/
|
*/
|
||||||
public state?: AnimationState;
|
public state?: AnimationState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The textureAtlas used by this widget to reference attachments. It's ready once assets are loaded.
|
* The textureAtlas used by this widget to reference attachments. It's ready once assets are loaded.
|
||||||
* Safely acces this property by using {@link loadingPromise}.
|
* Safely acces this property by using {@link whenReady}.
|
||||||
*/
|
*/
|
||||||
public textureAtlas?: TextureAtlas;
|
public textureAtlas?: TextureAtlas;
|
||||||
|
|
||||||
@ -701,7 +701,10 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
* A Promise that resolve to the widget itself once assets loading is terminated.
|
* A Promise that resolve to the widget itself once assets loading is terminated.
|
||||||
* Useful to safely access {@link skeleton} and {@link state} after a new widget has been just created.
|
* Useful to safely access {@link skeleton} and {@link state} after a new widget has been just created.
|
||||||
*/
|
*/
|
||||||
public loadingPromise: Promise<this>;
|
public get whenReady(): Promise<this> {
|
||||||
|
return this._whenReady;
|
||||||
|
};
|
||||||
|
private _whenReady: Promise<this>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the widget is in the assets loading process.
|
* If true, the widget is in the assets loading process.
|
||||||
@ -847,7 +850,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
this.root = this.attachShadow({ mode: "closed" });
|
this.root = this.attachShadow({ mode: "closed" });
|
||||||
|
|
||||||
// these two are terrible code smells
|
// these two are terrible code smells
|
||||||
this.loadingPromise = new Promise<this>((resolve) => {
|
this._whenReady = new Promise<this>((resolve) => {
|
||||||
this.resolveLoadingPromise = resolve;
|
this.resolveLoadingPromise = resolve;
|
||||||
});
|
});
|
||||||
this.overlayAssignedPromise = new Promise<void>((resolve) => {
|
this.overlayAssignedPromise = new Promise<void>((resolve) => {
|
||||||
@ -899,12 +902,14 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
* Remove the widget from the overlay and the DOM.
|
* Remove the widget from the overlay and the DOM.
|
||||||
*/
|
*/
|
||||||
dispose () {
|
dispose () {
|
||||||
this.remove();
|
this.disposed = true;
|
||||||
|
this.disposeGLResources();
|
||||||
this.loadingScreen?.dispose();
|
this.loadingScreen?.dispose();
|
||||||
|
this.overlay.removeWidget(this);
|
||||||
|
this.remove();
|
||||||
this.skeletonData = undefined;
|
this.skeletonData = undefined;
|
||||||
this.skeleton = undefined;
|
this.skeleton = undefined;
|
||||||
this.state = undefined;
|
this.state = undefined;
|
||||||
this.disposed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||||
@ -917,16 +922,17 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
/**
|
/**
|
||||||
* Starts the widget. Starting the widget means to load the assets currently set into
|
* Starts the widget. Starting the widget means to load the assets currently set into
|
||||||
* {@link atlasPath} and {@link skeletonPath}. If start is invoked when the widget is already started,
|
* {@link atlasPath} and {@link skeletonPath}. If start is invoked when the widget is already started,
|
||||||
* the skeleton, state, skin and animation will be reset.
|
* the skeleton, the state, and the bounds will be reset.
|
||||||
*/
|
*/
|
||||||
public start () {
|
public start () {
|
||||||
if (this.started) {
|
if (this.started) {
|
||||||
this.skeleton = undefined;
|
this.skeleton = undefined;
|
||||||
this.state = undefined;
|
this.state = undefined;
|
||||||
this._skin = undefined;
|
|
||||||
this._animation = undefined;
|
|
||||||
this.bounds.width = -1;
|
this.bounds.width = -1;
|
||||||
this.bounds.height = -1;
|
this.bounds.height = -1;
|
||||||
|
this._whenReady = new Promise<this>((resolve) => {
|
||||||
|
this.resolveLoadingPromise = resolve;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.started = true;
|
this.started = true;
|
||||||
|
|
||||||
@ -944,16 +950,34 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
* @param atlas the `TextureAtlas` from which to get the `TextureAtlasPage`s
|
* @param atlas the `TextureAtlas` from which to get the `TextureAtlasPage`s
|
||||||
* @returns The list of loaded assets
|
* @returns The list of loaded assets
|
||||||
*/
|
*/
|
||||||
public async loadTexturesInPagesAttribute (atlas: TextureAtlas): Promise<Array<any>> {
|
public async loadTexturesInPagesAttribute (): Promise<Array<any>> {
|
||||||
|
const atlas = this.overlay.assetManager.require(this.atlasPath!) as TextureAtlas;
|
||||||
const pagesIndexToLoad = this.pages ?? atlas.pages.map((_, i) => i); // if no pages provided, loads all
|
const pagesIndexToLoad = this.pages ?? atlas.pages.map((_, i) => i); // if no pages provided, loads all
|
||||||
const atlasPath = this.atlasPath?.includes("/") ? this.atlasPath.substring(0, this.atlasPath.lastIndexOf("/") + 1) : "";
|
const atlasPath = this.atlasPath?.includes("/") ? this.atlasPath.substring(0, this.atlasPath.lastIndexOf("/") + 1) : "";
|
||||||
const promisePageList: Array<Promise<any>> = [];
|
const promisePageList: Array<Promise<any>> = [];
|
||||||
|
const texturePaths = [];
|
||||||
|
|
||||||
for (const index of pagesIndexToLoad) {
|
for (const index of pagesIndexToLoad) {
|
||||||
const page = atlas.pages[index];
|
const page = atlas.pages[index];
|
||||||
const promiseTextureLoad = this.overlay.assetManager.loadTextureAsync(`${atlasPath}${page.name}`).then(texture => page.setTexture(texture));
|
const texturePath = `${atlasPath}${page.name}`;
|
||||||
|
texturePaths.push(texturePath);
|
||||||
|
|
||||||
|
const promiseTextureLoad = this.lastTexturePaths.includes(texturePath)
|
||||||
|
? Promise.resolve(texturePath)
|
||||||
|
: this.overlay.assetManager.loadTextureAsync(texturePath).then(texture => {
|
||||||
|
this.lastTexturePaths.push(texturePath);
|
||||||
|
page.setTexture(texture);
|
||||||
|
return texturePath;
|
||||||
|
});
|
||||||
|
|
||||||
promisePageList.push(promiseTextureLoad);
|
promisePageList.push(promiseTextureLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispose textures no longer used
|
||||||
|
for (const lastTexturePath of this.lastTexturePaths) {
|
||||||
|
if (!texturePaths.includes(lastTexturePath)) this.overlay.assetManager.disposeAsset(lastTexturePath);
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(promisePageList)
|
return Promise.all(promisePageList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,6 +1040,9 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
this.bounds = bounds;
|
this.bounds = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lastSkelPath = "";
|
||||||
|
private lastAtlasPath = "";
|
||||||
|
private lastTexturePaths: string[] = [];
|
||||||
// add a skeleton to the overlay and set the bounds to the given animation or to the setup pose
|
// add a skeleton to the overlay and set the bounds to the given animation or to the setup pose
|
||||||
private async loadSkeleton () {
|
private async loadSkeleton () {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@ -1032,17 +1059,33 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this ensure there is an overlay assigned because the overlay owns the asset manager
|
// this ensure there is an overlay assigned because the overlay owns the asset manager used to load assets below
|
||||||
await this.overlayAssignedPromise;
|
await this.overlayAssignedPromise;
|
||||||
|
|
||||||
|
if (this.lastSkelPath && this.lastSkelPath !== skeletonPath) {
|
||||||
|
this.overlay.assetManager.disposeAsset(this.lastSkelPath);
|
||||||
|
this.lastSkelPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lastAtlasPath && this.lastAtlasPath !== atlasPath) {
|
||||||
|
this.overlay.assetManager.disposeAsset(this.lastAtlasPath);
|
||||||
|
this.lastAtlasPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
// skeleton and atlas txt are loaded immeaditely
|
// skeleton and atlas txt are loaded immeaditely
|
||||||
// textures are loaeded depending on the 'pages' param:
|
// textures are loaeded depending on the 'pages' param:
|
||||||
// - [0,2]: only pages at index 0 and 2 are loaded
|
// - [0,2]: only pages at index 0 and 2 are loaded
|
||||||
// - []: no page is loaded
|
// - []: no page is loaded
|
||||||
// - undefined: all pages are loaded (default)
|
// - undefined: all pages are loaded (default)
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
isBinary ? this.overlay.assetManager.loadBinaryAsync(skeletonPath) : this.overlay.assetManager.loadJsonAsync(skeletonPath),
|
this.lastSkelPath ? Promise.resolve()
|
||||||
this.overlay.assetManager.loadTextureAtlasButNoTexturesAsync(atlasPath).then(atlas => this.loadTexturesInPagesAttribute(atlas)),
|
: (isBinary ? this.overlay.assetManager.loadBinaryAsync(skeletonPath) : this.overlay.assetManager.loadJsonAsync(skeletonPath))
|
||||||
|
.then(() => this.lastSkelPath = skeletonPath),
|
||||||
|
this.lastAtlasPath ? Promise.resolve()
|
||||||
|
: this.overlay.assetManager.loadTextureAtlasButNoTexturesAsync(atlasPath).then(atlas => {
|
||||||
|
this.lastAtlasPath = atlasPath;
|
||||||
|
this.loadTexturesInPagesAttribute();
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const atlas = this.overlay.assetManager.require(atlasPath) as TextureAtlas;
|
const atlas = this.overlay.assetManager.require(atlasPath) as TextureAtlas;
|
||||||
@ -1374,6 +1417,13 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private disposeGLResources() {
|
||||||
|
const { assetManager } = this.overlay;
|
||||||
|
if (this.lastAtlasPath) assetManager.disposeAsset(this.lastAtlasPath, this.identifier);
|
||||||
|
if (this.lastSkelPath) assetManager.disposeAsset(this.lastSkelPath);
|
||||||
|
for (const texturePath of this.lastTexturePaths) assetManager.disposeAsset(texturePath);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OverlayAttributes {
|
interface OverlayAttributes {
|
||||||
@ -1386,7 +1436,6 @@ interface OverlayAttributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes, Disposable {
|
class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes, Disposable {
|
||||||
|
|
||||||
private static OVERLAY_ID = "spine-overlay-default-identifier";
|
private static OVERLAY_ID = "spine-overlay-default-identifier";
|
||||||
private static OVERLAY_LIST = new Map<string, SpineWebComponentOverlay>();
|
private static OVERLAY_LIST = new Map<string, SpineWebComponentOverlay>();
|
||||||
|
|
||||||
@ -1689,13 +1738,20 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
|||||||
* Remove the overlay from the DOM, dispose all the contained widgets, and dispose the renderer.
|
* Remove the overlay from the DOM, dispose all the contained widgets, and dispose the renderer.
|
||||||
*/
|
*/
|
||||||
dispose (): void {
|
dispose (): void {
|
||||||
|
for (const widget of [...this.widgets]) widget.dispose();
|
||||||
|
|
||||||
this.remove();
|
this.remove();
|
||||||
this.widgets.forEach(widget => widget.dispose());
|
|
||||||
this.widgets.length = 0;
|
this.widgets.length = 0;
|
||||||
this.renderer.dispose();
|
this.renderer.dispose();
|
||||||
this.disposed = true;
|
this.disposed = true;
|
||||||
|
this.assetManager.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the widget to the overlay.
|
||||||
|
* If the widget is after the overlay in the DOM, the overlay is appended after the widget.
|
||||||
|
* @param widget The widget to add to the overlay
|
||||||
|
*/
|
||||||
addWidget (widget: SpineWebComponentWidget) {
|
addWidget (widget: SpineWebComponentWidget) {
|
||||||
this.widgets.push(widget);
|
this.widgets.push(widget);
|
||||||
this.intersectionObserver?.observe(widget.getHostElement());
|
this.intersectionObserver?.observe(widget.getHostElement());
|
||||||
@ -1708,6 +1764,19 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the widget from the overlay.
|
||||||
|
* @param widget The widget to remove from the overlay
|
||||||
|
*/
|
||||||
|
removeWidget (widget: SpineWebComponentWidget) {
|
||||||
|
const index = this.widgets.findIndex(w => w === widget);
|
||||||
|
if (index === -1) return false;
|
||||||
|
|
||||||
|
this.widgets.splice(index);
|
||||||
|
this.intersectionObserver?.unobserve(widget.getHostElement());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
addSlotFollowerElement (element: HTMLElement) {
|
addSlotFollowerElement (element: HTMLElement) {
|
||||||
this.boneFollowersParent.appendChild(element);
|
this.boneFollowersParent.appendChild(element);
|
||||||
this.resizedCallback();
|
this.resizedCallback();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user