mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
WIP - Added/Changed:
- overlay loading: now overlay is moved as the last element from where it is inserted to avoid widgets covered by backgrounds of html elements after it. - default overlayId - widget position in overlay coordinates (worldX, worldY) (experimental) - cursor position on widget world (cursorWorldX, cursorWorldY) (experimental) - jsonSkeletonKey: allow to load a specific skeleton in json containing multiple skeletons - onViewportManualStart: start the widget when in manual-start and enters the viewport the first time - overlayAssignedPromise: a promise that resolves when the overlay is assigned to the widget. Reads the comment on it - appendTo: to append the widget created using js and wait for the overlayAssignedPromise to resolve - changed how loadingPromise works - added cursorCanvasX, cursorCanvasY, cursorWorldX, cursorWorldY to overlay (experimental)
This commit is contained in:
parent
de7494036c
commit
0fa960251a
@ -1311,8 +1311,8 @@
|
||||
<br>
|
||||
<br>
|
||||
By default, assets are loaded immeaditely. You can postpone that by setting <code>manual-start="false"</code>.
|
||||
Then 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 skeleton or state.
|
||||
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>.
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@ -1343,7 +1343,7 @@
|
||||
});
|
||||
|
||||
// append the widget to the grid element
|
||||
gridElement.appendChild(widgetSection);
|
||||
await widgetSection.appendTo(gridElement);
|
||||
|
||||
// manually start the widget
|
||||
widgetSection.start();
|
||||
@ -1428,13 +1428,17 @@ skins.forEach((skin, i) => {
|
||||
When the widget (or the parent element) enters in the viewport, the callback <code>onScreenFunction</code> is invoked.
|
||||
<br>
|
||||
<br>
|
||||
By default, the callback call the widget <code>start</code> the first time the widget enters the viewport.
|
||||
That useful in combination with <code>manual-start="true</code> to load assets only when they are into the viewport.
|
||||
By default, the callback does two things:
|
||||
<ul>
|
||||
<li>set <code>onScreenAtLeastOnce</code> to <code>true</code> when the widget enters the viewport the first time</li>
|
||||
<li>if <code>manual-start</code> and <code>on-viewport-manual-start</code> are set the widget <code>start</code> is invoked
|
||||
the first time the widget enters the viewport and the assets are loaded only in that moment.</li>
|
||||
</ul>
|
||||
<br>
|
||||
The assets of the coin below are loaded only when the widget enters the viewport.
|
||||
<br>
|
||||
<br>
|
||||
You can overwrite that behaviour. For example, the raptor below changes animation everytime the widget enters the viewport.
|
||||
You can overwrite the <code>onScreenFunction</code> behaviour. For example, the raptor below changes animation everytime the widget enters the viewport.
|
||||
|
||||
</div>
|
||||
|
||||
@ -1444,7 +1448,8 @@ skins.forEach((skin, i) => {
|
||||
atlas="assets/coin-pma.atlas"
|
||||
skeleton="assets/coin-pro.skel"
|
||||
animation="animation"
|
||||
manual-start="true"
|
||||
manual-start
|
||||
on-viewport-manual-start
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="skin-grid-element">
|
||||
@ -1966,59 +1971,17 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div 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>isdraggable</code> property to <code>true</code>.
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
isdraggable
|
||||
></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"
|
||||
isdraggable="true"
|
||||
></spine-widget>`
|
||||
);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-left">
|
||||
If you use a spine widget in a scrollable element, the effect might not be the desired one. There will be two problems:
|
||||
If you use a spine widget in a element that has an ancestor that does not follow the webpage scroll, the effect might not be the desired one. You might encounter these problems:
|
||||
<br>
|
||||
<br>
|
||||
1) The widget will be slightly slower to scroll than the html behind <br>
|
||||
2) The widget will overflow the scrollable container until the html element container is visible <br>
|
||||
1) For scrollable containers, the widget will be slightly slower to scroll than the html behind. The effect is more evident for lower refresh rate display.<br>
|
||||
2) For scrollable containers, the widget will overflow the container bounds until the widget html element container is visible <br>
|
||||
3) For fixed containers, the widget will scroll in a jerky way <br>
|
||||
<br>
|
||||
In order to fix this behaviour, it is necessary to insert a dedicated <code>spine-overlay</code> webcomponent as a direct child of the scrollable container.
|
||||
In order to fix this behaviour, it is necessary to insert a dedicated <code>spine-overlay</code> webcomponent as a direct child of the container.
|
||||
Moreover, it is necessary to perform the following actions: <br>
|
||||
<br>
|
||||
1) The scrollable container must have a <code>transform</code> css attribute. If it hasn't this attribute the <code>spine-overlay</code> will add it for you.
|
||||
@ -2032,8 +1995,77 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
<br>
|
||||
<br>
|
||||
Additionally, you can set <code>overflow-top</code>, <code>overflow-bottom</code>, <code>overflow-left</code>, <code>overflow-right</code> attributes to the <code>spine-overlay</code> in order to make the canvas bigger and prevent scrolling artifacts.
|
||||
<br>
|
||||
<br>
|
||||
See the two examples below:
|
||||
<br>
|
||||
- Click the following button to open two elements with fixed positioned. The left one does not have a dedicated overlay and will scroll in a jerky way. <button id="popup-overlay-button-open">Open Popup</button>
|
||||
<br>
|
||||
- Below there are two scrolling items. The left one does not have a dedicated overlay, it will lag on scroll and the widgets will overflow the container.
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div id="popup-overlay" style="
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: none;
|
||||
justify-content: center; align-items: center; flex-direction: column;
|
||||
color: black;
|
||||
">
|
||||
<div style="display: flex; justify-content: center; align-items: center; flex-direction: column; gap: 10px; margin-bottom: 10px;">
|
||||
|
||||
<div id="popup" style="background-color: white; padding: 20px; text-align: center;">
|
||||
<spine-widget
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="armorgirl"
|
||||
animation="animation"
|
||||
style="width: 200px; height: 200px; border: 1px solid black;"
|
||||
></spine-widget>
|
||||
<br>
|
||||
This fixed element lags when scrolling.
|
||||
</div>
|
||||
|
||||
<div id="popup" style="background-color: white; padding: 20px; text-align: center;">
|
||||
<spine-overlay
|
||||
overlay-id="popup"
|
||||
scrollable
|
||||
scrollable-tweak-off
|
||||
></spine-overlay>
|
||||
<spine-widget
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="armorgirl"
|
||||
animation="animation"
|
||||
overlay-id="popup"
|
||||
style="width: 200px; height: 200px; border: 1px solid black;"
|
||||
></spine-widget>
|
||||
<br>
|
||||
This fixed element does not lag when scrolling.
|
||||
</div>
|
||||
</div>
|
||||
<button id="popup-overlay-button-close">Close Popup</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Get the buttons and popup elements
|
||||
const openPopupButton = document.getElementById('popup-overlay-button-open');
|
||||
const closePopupButton = document.getElementById('popup-overlay-button-close');
|
||||
const popupOverlay = document.getElementById('popup-overlay');
|
||||
|
||||
// Event listener to open the popup
|
||||
openPopupButton.addEventListener('click', function() {
|
||||
popupOverlay.style.display = 'flex';
|
||||
});
|
||||
|
||||
// Event listener to close the popup
|
||||
closePopupButton.addEventListener('click', function() {
|
||||
popupOverlay.style.display = 'none';
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="split-top split" style="justify-content: space-between">
|
||||
<div class="split-left" style="overflow-y: auto; width: 100px; height: 200px;">
|
||||
<div class="overflow-grid-container">
|
||||
@ -2091,6 +2123,150 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>escapeHTMLandInject(`
|
||||
// POPUP EXAMPLE
|
||||
|
||||
<div id="popup-overlay" style="
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: none;
|
||||
justify-content: center; align-items: center; flex-direction: column;
|
||||
color: black;
|
||||
">
|
||||
<div style="display: flex; justify-content: center; align-items: center; flex-direction: column; gap: 10px; margin-bottom: 10px;">
|
||||
|
||||
<div id="popup" style="background-color: white; padding: 20px; text-align: center;">
|
||||
<spine-widget
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="armorgirl"
|
||||
animation="animation"
|
||||
style="width: 200px; height: 200px; border: 1px solid black;"
|
||||
></spine-widget>
|
||||
<br>
|
||||
This fixed element lags when scrolling.
|
||||
</div>
|
||||
|
||||
<div id="popup" style="background-color: white; padding: 20px; text-align: center;">
|
||||
<spine-overlay
|
||||
overlay-id="popup"
|
||||
scrollable
|
||||
scrollable-tweak-off
|
||||
></spine-overlay>
|
||||
<spine-widget
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="armorgirl"
|
||||
animation="animation"
|
||||
overlay-id="popup"
|
||||
style="width: 200px; height: 200px; border: 1px solid black;"
|
||||
></spine-widget>
|
||||
<br>
|
||||
This fixed element does not lag when scrolling.
|
||||
</div>
|
||||
</div>
|
||||
<button id="popup-overlay-button-close">Close Popup</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
// SCROLLABLE CONTAINER EXAMPLE
|
||||
<div class="split-top split" style="justify-content: space-between">
|
||||
<div class="split-left" style="overflow-y: auto; width: 100px; height: 200px;">
|
||||
<div class="overflow-grid-container">
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-left" style="overflow-y: auto; width: 100px; height: 200px;">
|
||||
<spine-overlay
|
||||
overlay-id="scroll"
|
||||
scrollable
|
||||
scrollable-tweak-off
|
||||
overflow-top=".2"
|
||||
overflow-bottom=".2"
|
||||
overflow-left=".2"
|
||||
overflow-right=".2"
|
||||
></spine-overlay>
|
||||
<div class="overflow-grid-container">
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div class="section vertical-split" id="above-popup">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
As a bonus item, you can move you skeleton around just by setting the <code>isdraggable</code> property to <code>true</code>.
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
isdraggable
|
||||
></spine-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>escapeHTMLandInject(`
|
||||
@ -2105,6 +2281,250 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div class="section vertical-split" >
|
||||
<div class="split-left">
|
||||
If you need to determine the cursor position in the overlay world, you might find useful the following properties.
|
||||
<br>
|
||||
For <code>spine-widget</code>:
|
||||
<ul>
|
||||
<li><code>cursorWorldX</code> and <code>cursorWorldY</code> are the x and y of the cursor relative to the skeleton root (spine world).</li>
|
||||
<li><code>worldX</code> and <code>worldY</code> are the x and y of the root relative to the canvas/webgl context origin (spine world).</li>
|
||||
</ul>
|
||||
|
||||
For <code>spine-overlay</code>:
|
||||
<ul>
|
||||
<li><code>cursorCanvasX</code> and <code>cursorCanvasY</code> are the x and y of the cursor relative to the canvas top-left corner (screen world).</li>
|
||||
<li><code>cursorWorldX</code> and <code>cursorWorldY</code> are the x and y of the cursor relative to the canvas/webgl context origin (spine world).</li>
|
||||
</ul>
|
||||
|
||||
You can use these property to interact with your widget. See the following examples where the owl eyes will follow the cursor, even if you drag the owls in another position.
|
||||
Exaggerate the movement by deselection the checkbox below.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<label>
|
||||
<input type="checkbox" id="owl-checkbox" checked> Limit control bone movement
|
||||
</label>
|
||||
<br>
|
||||
<br>
|
||||
This feature is experimental and might be removed in the future.
|
||||
</div>
|
||||
|
||||
<div id="section-owls"></div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>escapeHTMLandInject(`
|
||||
<div id="section-owls"></div>
|
||||
|
||||
...
|
||||
|
||||
function createCircleOfDivs(numDivs = 8) {
|
||||
const container = document.createElement('div');
|
||||
container.style.position = 'relative';
|
||||
container.style.width = '400px';
|
||||
container.style.height = '400px';
|
||||
container.style.backgroundColor = '#f3f4f6';
|
||||
container.style.borderRadius = '50%';
|
||||
container.style.display = 'flex';
|
||||
container.style.justifyContent = 'center';
|
||||
container.style.alignItems = 'center';
|
||||
|
||||
const radius = 150;
|
||||
|
||||
for (let i = 0; i < numDivs; i++) {
|
||||
const angle = (i / numDivs) * 2 * Math.PI;
|
||||
const x = Math.cos(angle) * radius;
|
||||
const y = Math.sin(angle) * radius;
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.style.position = 'absolute';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
div.style.backgroundColor = '#3b82f6';
|
||||
div.style.borderRadius = '8px';
|
||||
div.style.display = 'flex';
|
||||
div.style.justifyContent = 'center';
|
||||
div.style.alignItems = 'center';
|
||||
div.style.color = 'white';
|
||||
div.style.fontWeight = 'bold';
|
||||
div.style.transform = \`translate(\${x}px, \${y}px)\`;
|
||||
div.innerHTML = \`
|
||||
<spine-widget
|
||||
identifier="owl\${i}"
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="owl"
|
||||
animation="idle"
|
||||
isdraggable
|
||||
></spine-widget>
|
||||
\`;
|
||||
|
||||
container.appendChild(div);
|
||||
|
||||
customElements.whenDefined('spine-widget').then(async () => {
|
||||
const widget = spine.getSpineWidget(\`owl\${i}\`);
|
||||
await widget.loadingPromise;
|
||||
widget.state.setAnimation(1, "blink", true)
|
||||
|
||||
const control = widget.skeleton.findBone("control");
|
||||
const tempVector = new spine.Vector3();
|
||||
const mouse = Ola({ x: 0, y: 0 }, 200);
|
||||
widget.afterUpdateWorldTransforms = () => {
|
||||
updateControl(widget, control, mouse, tempVector);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
document.getElementById('section-owls').appendChild(createCircleOfDivs(8));
|
||||
|
||||
const checkbox = document.getElementById('owl-checkbox');
|
||||
|
||||
let limitOwl = true;
|
||||
checkbox.addEventListener('change', () => limitOwl = checkbox.checked);
|
||||
|
||||
const updateControl = (widget, controlBone, mouse, tempVector) => {
|
||||
controlBone.parent.worldToLocal(tempVector.set(
|
||||
widget.cursorWorldX,
|
||||
widget.cursorWorldY,
|
||||
));
|
||||
|
||||
let x = tempVector.x;
|
||||
let y = tempVector.y;
|
||||
|
||||
if (limitOwl) {
|
||||
x = x / widget.overlay.canvas.width * 30;
|
||||
y = y / widget.overlay.canvas.height * 30;
|
||||
}
|
||||
|
||||
mouse.set({ x, y });
|
||||
|
||||
controlBone.x = controlBone.data.x + mouse.x;
|
||||
controlBone.y = controlBone.data.y + mouse.y;
|
||||
}
|
||||
`
|
||||
);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function createCircleOfDivs(numDivs = 8) {
|
||||
const container = document.createElement('div');
|
||||
container.style.position = 'relative';
|
||||
container.style.width = '400px';
|
||||
container.style.height = '400px';
|
||||
container.style.backgroundColor = '#f3f4f6';
|
||||
container.style.borderRadius = '50%';
|
||||
container.style.display = 'flex';
|
||||
container.style.justifyContent = 'center';
|
||||
container.style.alignItems = 'center';
|
||||
|
||||
const radius = 150;
|
||||
|
||||
for (let i = 0; i < numDivs; i++) {
|
||||
const angle = (i / numDivs) * 2 * Math.PI;
|
||||
const x = Math.cos(angle) * radius;
|
||||
const y = Math.sin(angle) * radius;
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.style.position = 'absolute';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
div.style.backgroundColor = '#3b82f6';
|
||||
div.style.borderRadius = '8px';
|
||||
div.style.display = 'flex';
|
||||
div.style.justifyContent = 'center';
|
||||
div.style.alignItems = 'center';
|
||||
div.style.color = 'white';
|
||||
div.style.fontWeight = 'bold';
|
||||
div.style.transform = `translate(${x}px, ${y}px)`;
|
||||
div.innerHTML = `
|
||||
<spine-widget
|
||||
identifier="owl${i}"
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="owl"
|
||||
animation="idle"
|
||||
isdraggable
|
||||
></spine-widget>
|
||||
`;
|
||||
|
||||
container.appendChild(div);
|
||||
|
||||
customElements.whenDefined('spine-widget').then(async () => {
|
||||
const widget = spine.getSpineWidget(`owl${i}`);
|
||||
await widget.loadingPromise;
|
||||
widget.state.setAnimation(1, "blink", true);
|
||||
|
||||
const control = widget.skeleton.findBone("control");
|
||||
const tempVector = new spine.Vector3();
|
||||
const mouse = Ola({ x: 0, y: 0 }, 200);
|
||||
widget.afterUpdateWorldTransforms = () => {
|
||||
updateControl(widget, control, mouse, tempVector);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
document.getElementById('section-owls').appendChild(createCircleOfDivs(8));
|
||||
|
||||
const checkbox = document.getElementById('owl-checkbox');
|
||||
|
||||
let limitOwl = true;
|
||||
checkbox.addEventListener('change', () => limitOwl = checkbox.checked);
|
||||
|
||||
const updateControl = (widget, controlBone, mouse, tempVector) => {
|
||||
controlBone.parent.worldToLocal(tempVector.set(
|
||||
widget.cursorWorldX,
|
||||
widget.cursorWorldY,
|
||||
));
|
||||
|
||||
let x = tempVector.x;
|
||||
let y = tempVector.y;
|
||||
|
||||
if (limitOwl) {
|
||||
x = x / widget.overlay.canvas.width * 30;
|
||||
y = y / widget.overlay.canvas.height * 30;
|
||||
}
|
||||
|
||||
mouse.set({ x, y });
|
||||
|
||||
controlBone.x = controlBone.data.x + mouse.x;
|
||||
controlBone.y = controlBone.data.y + mouse.y;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=global||self,global.Ola=factory())})(this,function(){"use strict";const position=(x0,v0,t1,t)=>{const a=(v0*t1+2*x0)/t1**3;const b=-(2*v0*t1+3*x0)/t1**2;const c=v0;const d=x0;return a*t**3+b*t**2+c*t+d};const speed=(x0,v0,t1,t)=>{const a=(v0*t1+2*x0)/t1**3;const b=-(2*v0*t1+3*x0)/t1**2;const c=v0;return 3*a*t**2+2*b*t+c};const each=function(values,cb){const multi=typeof values==="number"?{value:values}:values;Object.entries(multi).map(([key,value])=>cb(value,key))};function Single(init,time){this.start=new Date/1e3;this.time=time;this.from=init;this.current=init;this.to=init;this.speed=0}Single.prototype.get=function(now){const t=now/1e3-this.start;if(t<0){throw new Error("Cannot read in the past")}if(t>=this.time){return this.to}return this.to-position(this.to-this.from,this.speed,this.time,t)};Single.prototype.getSpeed=function(now){const t=now/1e3-this.start;if(t>=this.time){return 0}return speed(this.to-this.from,this.speed,this.time,t)};Single.prototype.set=function(value,time){const now=new Date;const current=this.get(now);this.speed=this.getSpeed(now);this.start=now/1e3;this.from=current;this.to=value;if(time){this.time=time}return current};function Ola(values,time=300){if(typeof values==="number"){values={value:values}}each(values,(init,key)=>{const value=new Single(init,time/1e3);Object.defineProperty(values,"_"+key,{value:value});Object.defineProperty(values,"$"+key,{get:()=>value.to});Object.defineProperty(values,key,{get:()=>value.get(new Date),set:val=>value.set(val),enumerable:true})});Object.defineProperty(values,"get",{get:()=>(function(name="value",now=new Date){return this["_"+name].get(now)})});Object.defineProperty(values,"set",{get:()=>(function(values,time=0){each(values,(value,key)=>{this["_"+key].set(value,time/1e3)})})});return values}return Ola});
|
||||
</script>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
<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>Webcomponent Tutorial</title>
|
||||
<style>
|
||||
body {
|
||||
@ -131,98 +130,44 @@
|
||||
}
|
||||
</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 //
|
||||
/////////////////////
|
||||
-->
|
||||
<!-- <div class="section vertical-split" id="section-popup">
|
||||
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split" style="justify-content: space-between">
|
||||
<!-- <div class="split-left" style="overflow-y: auto; width: 200px; height: 200px;">
|
||||
<div class="overflow-grid-container">
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel"></spine-widget></div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="split-left" style="overflow-y: auto; width: 200px; height: 200px;">
|
||||
<spine-overlay
|
||||
overlay-id="scroll"
|
||||
scrollable
|
||||
overflow-top=".2"
|
||||
overflow-bottom=".2"
|
||||
overflow-left=".2"
|
||||
overflow-right=".2"
|
||||
></spine-overlay>
|
||||
<div class="overflow-grid-container">
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
<div class="overflow-grid-item"><spine-widget atlas="assets/spineboy-pma.atlas" skeleton="assets/spineboy-pro.skel" overlay-id="scroll"></spine-widget></div>
|
||||
</div>
|
||||
<div class="split-top split">
|
||||
<div class="split-right" style="background-color: red;" id="inserting">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(async() => {
|
||||
const div = document.getElementById("inserting");
|
||||
const widget = spine.createSpineWidget({
|
||||
atlasPath: "assets/chibi-stickers-pma.atlas",
|
||||
skeletonPath: "assets/chibi-stickers.json",
|
||||
animation: "emotes/wave",
|
||||
skin: "soeren",
|
||||
manualStart: false,
|
||||
});
|
||||
|
||||
<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"
|
||||
isdraggable="true"
|
||||
></spine-widget>`
|
||||
);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
await widget.appendTo(div);
|
||||
|
||||
// widget.start();
|
||||
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
|
||||
<div style="height: 1000px;"> SPACE </div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
@ -230,9 +175,193 @@
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div class="section vertical-split" id="section-popup">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-right" style="background-color: red;">
|
||||
<spine-widget
|
||||
atlas="assets/raptor-pma.atlas"
|
||||
skeleton="assets/raptor-pro.skel"
|
||||
animation="walk"
|
||||
fit="fill"
|
||||
></spine-widget>
|
||||
</div>
|
||||
|
||||
<div class="split-right" style="background-color: red;">
|
||||
<spine-widget
|
||||
atlas="assets/raptor-pma.atlas"
|
||||
skeleton="assets/raptor-pro.skel"
|
||||
animation="walk"
|
||||
fit="fill"
|
||||
overlay-id="pippo"
|
||||
manual-start
|
||||
identifier="aaa"
|
||||
></spine-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<spine-overlay overlay-id="pippo"></spine-overlay>
|
||||
|
||||
<script>
|
||||
(async () => {
|
||||
const w = spine.getSpineWidget("aaa");
|
||||
|
||||
await w.overlayAssignedPromise;
|
||||
w.start();
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
<div class="section vertical-split" id="section-owls">
|
||||
<label>
|
||||
<input type="checkbox" id="owl-checkbox" checked> Limit control bone movement
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
function createCircleOfDivs(numDivs = 8) {
|
||||
const container = document.createElement('div');
|
||||
container.style.position = 'relative';
|
||||
container.style.width = '400px';
|
||||
container.style.height = '400px';
|
||||
container.style.backgroundColor = '#f3f4f6';
|
||||
container.style.borderRadius = '50%';
|
||||
container.style.display = 'flex';
|
||||
container.style.justifyContent = 'center';
|
||||
container.style.alignItems = 'center';
|
||||
|
||||
const radius = 150;
|
||||
|
||||
for (let i = 0; i < numDivs; i++) {
|
||||
const angle = (i / numDivs) * 2 * Math.PI;
|
||||
const x = Math.cos(angle) * radius;
|
||||
const y = Math.sin(angle) * radius;
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.style.position = 'absolute';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
div.style.backgroundColor = '#3b82f6';
|
||||
div.style.borderRadius = '8px';
|
||||
div.style.display = 'flex';
|
||||
div.style.justifyContent = 'center';
|
||||
div.style.alignItems = 'center';
|
||||
div.style.color = 'white';
|
||||
div.style.fontWeight = 'bold';
|
||||
div.style.transform = `translate(${x}px, ${y}px)`;
|
||||
div.textContent = i + 1;
|
||||
div.innerHTML = `
|
||||
<spine-widget
|
||||
identifier="pippo${i + 1}"
|
||||
atlas="../demos/assets/atlas2.atlas"
|
||||
skeleton="../demos/assets/demos.json"
|
||||
json-skeleton-key="owl"
|
||||
animation="idle"
|
||||
></spine-widget>
|
||||
`;
|
||||
|
||||
container.appendChild(div);
|
||||
|
||||
customElements.whenDefined('spine-widget').then(async () => {
|
||||
const widget = spine.getSpineWidget(`pippo${i+1}`);
|
||||
await widget.loadingPromise;
|
||||
widget.state.setAnimation(1, "blink", true)
|
||||
|
||||
const control = widget.skeleton.findBone("control");
|
||||
const tempVector = new spine.Vector3();
|
||||
const mouse = Ola({ x: 0, y: 0 }, 200);
|
||||
widget.afterUpdateWorldTransforms = () => {
|
||||
updateControl(widget, control, mouse, tempVector);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
// document.getElementById('section-owls').appendChild(createCircleOfDivs(1));
|
||||
}, 1000)
|
||||
|
||||
|
||||
const checkbox = document.getElementById('owl-checkbox');
|
||||
|
||||
let limitOwl = true;
|
||||
checkbox.addEventListener('change', () => {
|
||||
limitOwl = checkbox.checked;
|
||||
});
|
||||
|
||||
const updateControl = (widget, controlBone, mouse, tempVector) => {
|
||||
controlBone.parent.worldToLocal(tempVector.set(
|
||||
widget.cursorWorldX,
|
||||
widget.cursorWorldY,
|
||||
));
|
||||
|
||||
let x = tempVector.x;
|
||||
let y = tempVector.y;
|
||||
|
||||
if (limitOwl) {
|
||||
x = x / widget.overlay.canvas.width * 30;
|
||||
y = y / widget.overlay.canvas.height * 30;
|
||||
}
|
||||
|
||||
mouse.set({ x, y });
|
||||
|
||||
controlBone.x = controlBone.data.x + mouse.x;
|
||||
controlBone.y = controlBone.data.y + mouse.y;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
spine.SpineWebComponentWidget.SHOW_FPS = true;
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=global||self,global.Ola=factory())})(this,function(){"use strict";const position=(x0,v0,t1,t)=>{const a=(v0*t1+2*x0)/t1**3;const b=-(2*v0*t1+3*x0)/t1**2;const c=v0;const d=x0;return a*t**3+b*t**2+c*t+d};const speed=(x0,v0,t1,t)=>{const a=(v0*t1+2*x0)/t1**3;const b=-(2*v0*t1+3*x0)/t1**2;const c=v0;return 3*a*t**2+2*b*t+c};const each=function(values,cb){const multi=typeof values==="number"?{value:values}:values;Object.entries(multi).map(([key,value])=>cb(value,key))};function Single(init,time){this.start=new Date/1e3;this.time=time;this.from=init;this.current=init;this.to=init;this.speed=0}Single.prototype.get=function(now){const t=now/1e3-this.start;if(t<0){throw new Error("Cannot read in the past")}if(t>=this.time){return this.to}return this.to-position(this.to-this.from,this.speed,this.time,t)};Single.prototype.getSpeed=function(now){const t=now/1e3-this.start;if(t>=this.time){return 0}return speed(this.to-this.from,this.speed,this.time,t)};Single.prototype.set=function(value,time){const now=new Date;const current=this.get(now);this.speed=this.getSpeed(now);this.start=now/1e3;this.from=current;this.to=value;if(time){this.time=time}return current};function Ola(values,time=300){if(typeof values==="number"){values={value:values}}each(values,(init,key)=>{const value=new Single(init,time/1e3);Object.defineProperty(values,"_"+key,{value:value});Object.defineProperty(values,"$"+key,{get:()=>value.to});Object.defineProperty(values,key,{get:()=>value.get(new Date),set:val=>value.set(val),enumerable:true})});Object.defineProperty(values,"get",{get:()=>(function(name="value",now=new Date){return this["_"+name].get(now)})});Object.defineProperty(values,"set",{get:()=>(function(values,time=0){each(values,(value,key)=>{this["_"+key].set(value,time/1e3)})})});return values}return Ola});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -101,6 +101,7 @@ export type AttributeTypes = "string" | "number" | "boolean" | "string-number" |
|
||||
interface WidgetAttributes {
|
||||
atlasPath?: string
|
||||
skeletonPath?: string
|
||||
jsonSkeletonKey?: string
|
||||
scale: number
|
||||
animation?: string
|
||||
skin?: string
|
||||
@ -125,6 +126,7 @@ interface WidgetAttributes {
|
||||
debug: boolean
|
||||
identifier: string
|
||||
manualStart: boolean
|
||||
onViewportManualStart: boolean
|
||||
pages?: Array<number>
|
||||
clip: boolean
|
||||
offScreenUpdateBehaviour: OffScreenUpdateBehaviourType
|
||||
@ -165,6 +167,28 @@ interface WidgetInternalProperties {
|
||||
|
||||
export class SpineWebComponentWidget extends HTMLElement implements Disposable, WidgetAttributes, WidgetOverridableMethods, WidgetInternalProperties, Partial<WidgetPublicProperties> {
|
||||
|
||||
public worldX = 0;
|
||||
public worldY = 0;
|
||||
public cursorWorldX = 1;
|
||||
public cursorWorldY = 1;
|
||||
public jsonSkeletonKey?: string;
|
||||
public onViewportManualStart = false;
|
||||
|
||||
// this promise in necessary only for manual start. Before calling manual start is necessary that the overlay has been assigned to the widget.
|
||||
// overlay assignment is asynchronous due to webcomponent promotion and dom load termination.
|
||||
// When manual start is false, loadSkeleton is invoked after the overlay is assigned. loadSkeleton needs the assetManager that is owned by the overlay.
|
||||
// the overlay owns the assetManager because the overly owns the gl context.
|
||||
// if it wasn't for the gl context with which textures are created, we could:
|
||||
// - have a unique asset manager independent from the overlay (we literally reload the same assets in two different overlays)
|
||||
// - remove overlayAssignedPromise and the needs to wait for its resolving
|
||||
// - remove appendTo that is just to avoid the user to use the overlayAssignedPromise when the widget is created using js
|
||||
public overlayAssignedPromise: Promise<void>;
|
||||
|
||||
public async appendTo(element: HTMLElement): Promise<void> {
|
||||
element.appendChild(this);
|
||||
await this.overlayAssignedPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, enables a top-left span showing FPS (it has black text)
|
||||
*/
|
||||
@ -464,7 +488,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
if (widget.loading && !widget.onScreenAtLeastOnce) {
|
||||
widget.onScreenAtLeastOnce = true;
|
||||
|
||||
if (widget.manualStart) {
|
||||
if (widget.manualStart && widget.onViewportManualStart) {
|
||||
widget.start();
|
||||
}
|
||||
}
|
||||
@ -492,7 +516,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
* 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.
|
||||
*/
|
||||
public loadingPromise?: Promise<this>;
|
||||
public loadingPromise: Promise<this>;
|
||||
|
||||
/**
|
||||
* If true, the widget is in the assets loading process.
|
||||
@ -575,9 +599,16 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
// Reference to the overlay webcomponent
|
||||
private overlay!: SpineWebComponentOverlay;
|
||||
|
||||
// Invoked when widget is ready
|
||||
private resolveLoadingPromise!: (value: this | PromiseLike<this>) => void;
|
||||
|
||||
// Invoked when widget has an overlay assigned
|
||||
private resolveOverlayAssignedPromise!: () => void;
|
||||
|
||||
static attributesDescription: Record<string, { propertyName: keyof WidgetAttributes, type: AttributeTypes, defaultValue?: any }> = {
|
||||
atlas: { propertyName: "atlasPath", type: "string" },
|
||||
skeleton: { propertyName: "skeletonPath", type: "string" },
|
||||
"json-skeleton-key": { propertyName: "jsonSkeletonKey", type: "string" },
|
||||
scale: { propertyName: "scale", type: "number" },
|
||||
animation: { propertyName: "animation", type: "string", defaultValue: undefined },
|
||||
skin: { propertyName: "skin", type: "string" },
|
||||
@ -600,6 +631,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
identifier: { propertyName: "identifier", type: "string" },
|
||||
debug: { propertyName: "debug", type: "boolean" },
|
||||
"manual-start": { propertyName: "manualStart", type: "boolean" },
|
||||
"on-viewport-manual-start": { propertyName: "onViewportManualStart", type: "boolean" },
|
||||
spinner: { propertyName: "loadingSpinner", type: "boolean" },
|
||||
clip: { propertyName: "clip", type: "boolean" },
|
||||
pages: { propertyName: "pages", type: "string-number" },
|
||||
@ -620,6 +652,14 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
this.debugDragDiv.style.position = "absolute";
|
||||
this.debugDragDiv.style.backgroundColor = "rgba(255, 0, 0, .3)";
|
||||
this.debugDragDiv.style.setProperty("pointer-events", "none");
|
||||
|
||||
// these two are terrible code smells
|
||||
this.loadingPromise = new Promise<this>((resolve) => {
|
||||
this.resolveLoadingPromise = resolve;
|
||||
});
|
||||
this.overlayAssignedPromise = new Promise<void>((resolve) => {
|
||||
this.resolveOverlayAssignedPromise = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback () {
|
||||
@ -627,17 +667,35 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
throw new Error("You cannot attach a disposed widget");
|
||||
};
|
||||
|
||||
customElements.whenDefined("spine-overlay").then(() => {
|
||||
if (!this.overlay) this.overlay = this.initializeOverlay(this.getAttribute("overlay-id"));
|
||||
this.overlay.addWidget(this);
|
||||
});
|
||||
if (!this.manualStart && !this.started) {
|
||||
this.start();
|
||||
if (this.overlay) {
|
||||
this.initAfterConnect();
|
||||
} else {
|
||||
window.addEventListener("DOMContentLoaded", this.DOMContentLoadedHandler);
|
||||
if (document.readyState !== "loading") {
|
||||
this.DOMContentLoadedHandler();
|
||||
}
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
private initAfterConnect() {
|
||||
this.overlay.addWidget(this);
|
||||
if (!this.manualStart && !this.started) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
private DOMContentLoadedHandler = () => {
|
||||
customElements.whenDefined("spine-overlay").then(async () => {
|
||||
this.overlay = SpineWebComponentOverlay.getOrCreateOverlay(this.getAttribute("overlay-id"));
|
||||
this.resolveOverlayAssignedPromise();
|
||||
this.initAfterConnect();
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback (): void {
|
||||
window.removeEventListener("DOMContentLoaded", this.DOMContentLoadedHandler);
|
||||
const index = this.overlay!.skeletonList.indexOf(this);
|
||||
if (index !== -1) {
|
||||
this.overlay!.skeletonList.splice(index, 1);
|
||||
@ -677,7 +735,9 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
this.loadingPromise = customElements.whenDefined("spine-overlay").then(() => this.loadSkeleton());
|
||||
customElements.whenDefined("spine-overlay").then(() => {
|
||||
this.resolveLoadingPromise(this.loadSkeleton());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -755,7 +815,8 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
const skeletonLoader = isBinary ? new SkeletonBinary(atlasLoader) : new SkeletonJson(atlasLoader);
|
||||
skeletonLoader.scale = scale;
|
||||
|
||||
const skeletonFile = this.overlay.assetManager.require(skeletonPath);
|
||||
const skeletonFileAsset = this.overlay.assetManager.require(skeletonPath);
|
||||
const skeletonFile = this.jsonSkeletonKey ? skeletonFileAsset[this.jsonSkeletonKey] : skeletonFileAsset;
|
||||
const skeletonData = (skeletonDataInput || this.skeleton?.data) ?? skeletonLoader.readSkeletonData(skeletonFile);
|
||||
|
||||
const skeleton = new Skeleton(skeletonData);
|
||||
@ -823,19 +884,6 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
`;
|
||||
}
|
||||
|
||||
// Create a new overlay webcomponent, if no one exists yet.
|
||||
// TODO: allow the possibility to instantiate multiple overlay (eg: background, foreground),
|
||||
// to give them an identifier, and to specify which overlay is assigned to a widget
|
||||
private initializeOverlay (overlayId: string | null): SpineWebComponentOverlay {
|
||||
const queryString = overlayId === null ? "spine-overlay:not([overlay-id])" : `spine-overlay[overlay-id=${overlayId}]`;
|
||||
let overlay = this.overlay || document.querySelector(queryString) as SpineWebComponentOverlay;
|
||||
if (!overlay) {
|
||||
overlay = document.createElement("spine-overlay") as SpineWebComponentOverlay;
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
/*
|
||||
* Other utilities
|
||||
*/
|
||||
@ -898,6 +946,18 @@ interface OverlayAttributes {
|
||||
|
||||
class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes, Disposable {
|
||||
|
||||
public static OVERLAY_ID = "spine-overlay-default-identifier";
|
||||
public static OVERLAY_LIST = new Map<string, SpineWebComponentOverlay>();
|
||||
static getOrCreateOverlay(overlayId: string | null): SpineWebComponentOverlay {
|
||||
let overlay = SpineWebComponentOverlay.OVERLAY_LIST.get(overlayId || SpineWebComponentOverlay.OVERLAY_ID);
|
||||
if (!overlay) {
|
||||
overlay = document.createElement('spine-overlay') as SpineWebComponentOverlay;
|
||||
overlay.setAttribute('overlay-id', SpineWebComponentOverlay.OVERLAY_ID);
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
public skeletonList = new Array<SpineWebComponentWidget>();
|
||||
public renderer: SceneRenderer;
|
||||
public assetManager: AssetManager;
|
||||
@ -919,7 +979,7 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
// be aware that the canvas is already big as the display size
|
||||
// making it bigger might reduce performance significantly
|
||||
public overflowTop = .2;
|
||||
public overflowBottom = .0;
|
||||
public overflowBottom = .2;
|
||||
public overflowLeft = .0;
|
||||
public overflowRight = .0;
|
||||
private overflowLeftSize = 0;
|
||||
@ -968,51 +1028,17 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
this.assetManager = new AssetManager(context);
|
||||
}
|
||||
|
||||
static attributesDescription: Record<string, { propertyName: keyof OverlayAttributes, type: AttributeTypes, defaultValue?: any }> = {
|
||||
"overlay-id": { propertyName: "overlayId", type: "string" },
|
||||
"scrollable": { propertyName: "scrollable", type: "boolean" },
|
||||
"overflow-top": { propertyName: "overflowTop", type: "number" },
|
||||
"overflow-bottom": { propertyName: "overflowBottom", type: "number" },
|
||||
"overflow-left": { propertyName: "overflowLeft", type: "number" },
|
||||
"overflow-right": { propertyName: "overflowRight", type: "number" },
|
||||
}
|
||||
|
||||
static get observedAttributes (): string[] {
|
||||
return Object.keys(SpineWebComponentOverlay.attributesDescription);
|
||||
}
|
||||
|
||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||
const { type, propertyName, defaultValue } = SpineWebComponentOverlay.attributesDescription[name];
|
||||
const val = castValue(type, newValue, defaultValue);
|
||||
(this as any)[propertyName] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
private resizeCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
this.zoomHandler();
|
||||
}
|
||||
|
||||
private orientationChangeCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
// after an orientation change the scrolling changes, but the scroll event does not fire
|
||||
this.scrollHandler();
|
||||
}
|
||||
|
||||
// right now, we scroll the canvas each frame before rendering loop, that makes scrolling on mobile waaay more smoother
|
||||
// this is way scroll handler do nothing
|
||||
private scrollHandler = () => {
|
||||
// this.translateCanvas();
|
||||
}
|
||||
|
||||
private onLoadCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
this.zoomHandler();
|
||||
this.scrollHandler();
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
connectedCallback (): void {
|
||||
let overlayId = this.getAttribute('overlay-id');
|
||||
if (!overlayId) {
|
||||
overlayId = SpineWebComponentOverlay.OVERLAY_ID;
|
||||
this.setAttribute('overlay-id', overlayId);
|
||||
}
|
||||
const existingOverlay = SpineWebComponentOverlay.OVERLAY_LIST.get(overlayId);
|
||||
if (existingOverlay && existingOverlay !== this) {
|
||||
throw new Error(`"SpineWebComponentOverlay - You cannot have two spine-overlay with the same overlay-id: ${overlayId}"`);
|
||||
}
|
||||
SpineWebComponentOverlay.OVERLAY_LIST.set(overlayId, this);
|
||||
// window.addEventListener("scroll", this.scrollHandler);
|
||||
window.addEventListener("load", this.onLoadCallback);
|
||||
if (this.loaded) this.onLoadCallback();
|
||||
@ -1058,7 +1084,10 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
this.startRenderingLoop();
|
||||
}
|
||||
|
||||
private running = false;
|
||||
disconnectedCallback (): void {
|
||||
const id = this.getAttribute('id');
|
||||
if (id) SpineWebComponentOverlay.OVERLAY_LIST.delete(id);
|
||||
// window.removeEventListener("scroll", this.scrollHandler);
|
||||
window.removeEventListener("load", this.onLoadCallback);
|
||||
window.screen.orientation.removeEventListener('change', this.orientationChangeCallback);
|
||||
@ -1067,6 +1096,54 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
this.input?.dispose();
|
||||
}
|
||||
|
||||
|
||||
static attributesDescription: Record<string, { propertyName: keyof OverlayAttributes, type: AttributeTypes, defaultValue?: any }> = {
|
||||
"overlay-id": { propertyName: "overlayId", type: "string" },
|
||||
"scrollable": { propertyName: "scrollable", type: "boolean" },
|
||||
"overflow-top": { propertyName: "overflowTop", type: "number" },
|
||||
"overflow-bottom": { propertyName: "overflowBottom", type: "number" },
|
||||
"overflow-left": { propertyName: "overflowLeft", type: "number" },
|
||||
"overflow-right": { propertyName: "overflowRight", type: "number" },
|
||||
}
|
||||
|
||||
static get observedAttributes (): string[] {
|
||||
return Object.keys(SpineWebComponentOverlay.attributesDescription);
|
||||
}
|
||||
|
||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||
const { type, propertyName, defaultValue } = SpineWebComponentOverlay.attributesDescription[name];
|
||||
const val = castValue(type, newValue, defaultValue);
|
||||
(this as any)[propertyName] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
private resizeCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
this.zoomHandler();
|
||||
}
|
||||
|
||||
private orientationChangeCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
// after an orientation change the scrolling changes, but the scroll event does not fire
|
||||
this.scrollHandler();
|
||||
}
|
||||
|
||||
// right now, we scroll the canvas each frame before rendering loop, that makes scrolling on mobile waaay more smoother
|
||||
// this is way scroll handler do nothing
|
||||
private scrollHandler = () => {
|
||||
// this.translateCanvas();
|
||||
}
|
||||
|
||||
private onLoadCallback = () => {
|
||||
this.updateCanvasSize();
|
||||
this.zoomHandler();
|
||||
this.scrollHandler();
|
||||
if (!this.loaded) {
|
||||
this.parentElement!.appendChild(this);
|
||||
}
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
dispose (): void {
|
||||
this.remove();
|
||||
this.skeletonList.length = 0;
|
||||
@ -1077,9 +1154,14 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
addWidget (widget: SpineWebComponentWidget) {
|
||||
this.skeletonList.push(widget);
|
||||
this.intersectionObserver?.observe(widget.getHTMLElementReference());
|
||||
if (this.loaded) {
|
||||
this.parentElement!.appendChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
private startRenderingLoop () {
|
||||
if (this.running) return;
|
||||
|
||||
const updateWidgets = () => {
|
||||
const delta = this.time.delta;
|
||||
this.skeletonList.forEach(({ skeleton, state, update, onScreen, offScreenUpdateBehaviour, beforeUpdateWorldTransforms, afterUpdateWorldTransforms }) => {
|
||||
@ -1289,6 +1371,9 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
const worldOffsetX = divOriginX + offsetX + dragX;
|
||||
const worldOffsetY = divOriginY + offsetY + dragY;
|
||||
|
||||
widget.worldX = worldOffsetX;
|
||||
widget.worldY = worldOffsetY;
|
||||
|
||||
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
|
||||
for (let i = 0; i < size; i += vertexSize) {
|
||||
vertices[i] = vertices[i] + worldOffsetX;
|
||||
@ -1310,7 +1395,9 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
widget.dragBoundsRectangle.y += divBounds.y;
|
||||
}
|
||||
|
||||
if (!widget.debugDragDiv.isConnected) document.body.appendChild(widget.debugDragDiv);
|
||||
if (debug && !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`;
|
||||
@ -1361,7 +1448,10 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
}
|
||||
|
||||
const loop = () => {
|
||||
if (this.disposed || !this.isConnected) return;
|
||||
if (this.disposed || !this.isConnected) {
|
||||
this.running = false;
|
||||
return;
|
||||
};
|
||||
requestAnimationFrame(loop);
|
||||
if (!this.loaded) return;
|
||||
this.time.update();
|
||||
@ -1371,6 +1461,7 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
}
|
||||
|
||||
requestAnimationFrame(loop);
|
||||
this.running = true;
|
||||
|
||||
const red = new Color(1, 0, 0, 1);
|
||||
const green = new Color(0, 1, 0, 1);
|
||||
@ -1378,10 +1469,16 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
const transparentWhite = new Color(1, 1, 1, .3);
|
||||
}
|
||||
|
||||
public cursorCanvasX = 1;
|
||||
public cursorCanvasY = 1;
|
||||
public cursorWorldX = 1;
|
||||
public cursorWorldY = 1;
|
||||
|
||||
private setupDragUtility (): Input {
|
||||
// TODO: we should use document - body might have some margin that offset the click events - Meanwhile I take event pageX/Y
|
||||
const inputManager = new Input(document.body, false)
|
||||
const point: Point = { x: 0, y: 0 };
|
||||
const tempVector = new Vector3();
|
||||
|
||||
const getInput = (ev?: MouseEvent | TouchEvent): Point => {
|
||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||
@ -1393,6 +1490,29 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
let prevX = 0;
|
||||
let prevY = 0;
|
||||
inputManager.addListener({
|
||||
// moved is used to pass curson position wrt to canvas and widget position and currently is EXPERIMENTAL
|
||||
moved: (x, y, ev) => {
|
||||
const input = getInput(ev);
|
||||
this.cursorCanvasX = input.x - window.scrollX;
|
||||
this.cursorCanvasY = input.y - window.scrollY;
|
||||
|
||||
const ref = this.parentElement!.getBoundingClientRect();
|
||||
if (this.scrollable) {
|
||||
this.cursorCanvasX -= ref.left;
|
||||
this.cursorCanvasY -= ref.top;
|
||||
}
|
||||
|
||||
tempVector.set(this.cursorCanvasX, this.cursorCanvasY, 0);
|
||||
this.renderer.camera.screenToWorld(tempVector, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
|
||||
if (Number.isNaN(tempVector.x) || Number.isNaN(tempVector.y)) return;
|
||||
this.cursorWorldX = tempVector.x;
|
||||
this.cursorWorldY = tempVector.y;
|
||||
this.skeletonList.forEach(widget => {
|
||||
widget.cursorWorldX = this.cursorWorldX - widget.worldX;
|
||||
widget.cursorWorldY = this.cursorWorldY - widget.worldY;
|
||||
});
|
||||
},
|
||||
down: (x, y, ev) => {
|
||||
const input = getInput(ev);
|
||||
this.skeletonList.forEach(widget => {
|
||||
@ -1463,7 +1583,7 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
|
||||
private resizeCanvas () {
|
||||
let width, height;
|
||||
if (!this.overlayId) {
|
||||
if (!this.scrollable) {
|
||||
const screenSize = this.getScreenSize();
|
||||
width = screenSize.width;
|
||||
height = screenSize.height;
|
||||
@ -1472,7 +1592,6 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
|
||||
height = this.parentElement!.clientHeight;
|
||||
}
|
||||
|
||||
|
||||
// this is needed because screen size is wrong when zoom levels occurs
|
||||
// zooming out will make the canvas smaller and its known that zoom level
|
||||
// on browsers is not reliable
|
||||
@ -1603,10 +1722,6 @@ export function createSpineWidget (parameters: WidgetAttributes): SpineWebCompon
|
||||
if (value) widget.setAttribute(key, value as any);
|
||||
});
|
||||
|
||||
if (!widget.manualStart) {
|
||||
widget.start();
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user