[ts][player] Fixed text selection on speed slider modification in FF, added snapping to speed slider, added hiding timeline if mouse doesn't move for 1 second except when popup is active or mouse is over controls, decided against popup centered over button, removed Show prefix from debug popup, added hiding buttons if there is only one skin/animation, fixed control bone not moving when paused.

This commit is contained in:
badlogic 2018-11-14 14:29:27 +01:00
parent 8b49ad91cb
commit 94eec340c4
7 changed files with 12094 additions and 11964 deletions

View File

@ -444,7 +444,7 @@ void test (SkeletonData* skeletonData, Atlas* atlas) {
Skeleton skeleton(skeletonData);
AnimationStateData animationStateData(skeletonData);
AnimationState animationState(&animationStateData);
animationState.setAnimation(0, "drive", true);
animationState.setAnimation(0, "idle", true);
float d = 3;
for (int i = 0; i < 1; i++) {
@ -459,6 +459,7 @@ int main () {
DebugExtension dbgExtension(SpineExtension::getInstance());
SpineExtension::setInstance(&dbgExtension);
testcase(test, "data/yellow_god.json", "data/yellow_god.skel", "data/yellow_god.atlas", 0.6f);
testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy.atlas", 0.6f);
testcase(stretchymanStrechyIk, "data/stretchyman-stretchy-ik.json", "data/stretchyman-stretchy-ik.skel", "data/stretchyman.atlas", 0.6f);
testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -152,6 +152,8 @@
right: 2px;
bottom: 42px;
border-radius: 4px;
max-height: 400%;
overflow: auto;
}
.spine-player-popup-title {
@ -180,13 +182,17 @@
bottom: 0;
left: 0;
width: 100%;
opacity: 0;
transition: opacity 0.2s;
}
.spine-player:hover .spine-player-controls {
.spine-player-controls.hidden {
pointer-events: none;
opacity: 0;
transition: opacity 0.4s;
}
.spine-player-controls.visible {
opacity: 1;
transition: opacity 0.2s;
transition: opacity 0.4s;
}
/** Player buttons **/
@ -208,7 +214,7 @@
height: 32px;
background-size: 20px;
background-repeat: no-repeat;
background-position: 6;
background-position: center;
cursor: pointer;
}

View File

@ -1,15 +1,21 @@
<!doctype html>
<html>
<script src="../../build/spine-widget.js"></script>
<link rel="stylesheet" href="../css/spine-player.css">
<head>
<meta charset="utf-8">
<script src="../../build/spine-widget.js"></script>
<link rel="stylesheet" href="../css/spine-player.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<style>
body {
background: gray;
margin: 0px;
}
</style>
<body>
<div id="container" style="width: 100%; height: 100%;"></div>
<div id="container" style="width: 100%; height: 100vh;"></div>
</body>
<script>
new spine.SpinePlayer(document.getElementById("container"), {
@ -17,7 +23,8 @@ body {
atlasUrl: "assets/spineboy.atlas",
animations: ["walk", "jump"],
controlBones: ["root"],
backgroundColor: "#cccccc"
backgroundColor: "#cccccc",
showControls: false,
});
</script>
</body>

View File

@ -170,6 +170,8 @@
private value: HTMLElement;
public change: (percentage: number) => void;
constructor(public snaps = 0, public snapPercentage = 0.1) { }
render(): HTMLElement {
this.slider = createElement(/*html*/`
<div class="spine-player-slider">
@ -188,7 +190,7 @@
up: (x, y) => {
dragging = false;
let percentage = x / this.slider.clientWidth;
percentage = Math.max(0, Math.min(percentage, 1));
percentage = percentage = Math.max(0, Math.min(percentage, 1));
this.setValue(x / this.slider.clientWidth);
if (this.change) this.change(percentage);
},
@ -196,23 +198,34 @@
if (dragging) {
let percentage = x / this.slider.clientWidth;
percentage = Math.max(0, Math.min(percentage, 1));
this.setValue(x / this.slider.clientWidth);
percentage = this.setValue(x / this.slider.clientWidth);
if (this.change) this.change(percentage);
}
},
dragged: (x, y) => {
let percentage = x / this.slider.clientWidth;
percentage = Math.max(0, Math.min(percentage, 1));
this.setValue(x / this.slider.clientWidth);
percentage = this.setValue(x / this.slider.clientWidth);
if (this.change) this.change(percentage);
}
});
return this.slider;
}
setValue(percentage: number) {
setValue(percentage: number): number {
percentage = Math.max(0, Math.min(1, percentage));
if (this.snaps > 0) {
let modulo = percentage % (1 / this.snaps);
// floor
if (modulo < (1 / this.snaps) * this.snapPercentage) {
percentage = percentage - modulo;
} else if (modulo > (1 / this.snaps) - (1 / this.snaps) * this.snapPercentage) {
percentage = percentage - modulo + (1 / this.snaps);
}
percentage = Math.max(0, Math.min(1, percentage));
}
this.value.style.width = "" + (percentage * 100) + "%";
return percentage;
}
}
@ -228,6 +241,8 @@
private canvas: HTMLCanvasElement;
private timelineSlider: Slider;
private playButton: HTMLElement;
private skinButton: HTMLElement;
private animationButton: HTMLElement;
private context: spine.webgl.ManagedWebGLRenderingContext;
private loadingScreen: spine.webgl.LoadingScreen;
@ -303,7 +318,7 @@
<div class="spine-player">
<canvas class="spine-player-canvas"></canvas>
<div class="spine-player-error spine-player-hidden"></div>
<div class="spine-player-controls spine-player-popup-parent">
<div class="spine-player-controls spine-player-popup-parent hidden">
<div class="spine-player-timeline">
</div>
<div class="spine-player-buttons">
@ -357,8 +372,8 @@
timeline.appendChild(this.timelineSlider.render());
this.playButton = findWithId(dom, "spine-player-button-play-pause")[0];
let speedButton = findWithId(dom, "spine-player-button-speed")[0];
let animationButton = findWithId(dom, "spine-player-button-animation")[0];
let skinButton = findWithId(dom, "spine-player-button-skin")[0];
this.animationButton = findWithId(dom, "spine-player-button-animation")[0];
this.skinButton = findWithId(dom, "spine-player-button-skin")[0];
let settingsButton = findWithId(dom, "spine-player-button-settings")[0];
let fullscreenButton = findWithId(dom, "spine-player-button-fullscreen")[0];
@ -371,11 +386,11 @@
this.showSpeedDialog();
}
animationButton.onclick = () => {
this.animationButton.onclick = () => {
this.showAnimationsDialog();
}
skinButton.onclick = () => {
this.skinButton.onclick = () => {
this.showSkinsDialog();
}
@ -404,8 +419,6 @@
this.drawFrame(false);
}
if (!config.showControls) findWithClass(dom, "spine-player-controls ")[0].classList.add("spine-player-hidden");
return dom;
}
@ -424,7 +437,7 @@
</div>
`);
let sliderParent = findWithClass(popup.dom, "spine-player-speed-slider")[0];
let slider = new Slider();
let slider = new Slider(2);
sliderParent.appendChild(slider.render());
slider.setValue(this.speed / 2);
slider.change = (percentage) => {
@ -532,14 +545,14 @@
rows.appendChild(row);
};
makeItem("Show bones", "bones");
makeItem("Show regions", "regions");
makeItem("Show meshes", "meshes");
makeItem("Show bounds", "bounds");
makeItem("Show paths", "paths");
makeItem("Show clipping", "clipping");
makeItem("Show points", "points");
makeItem("Show hulls", "hulls");
makeItem("Bones", "bones");
makeItem("Regions", "regions");
makeItem("Meshes", "meshes");
makeItem("Bounds", "bounds");
makeItem("Paths", "paths");
makeItem("Clipping", "clipping");
makeItem("Points", "points");
makeItem("Hulls", "hulls");
popup.show();
}
@ -580,9 +593,10 @@
this.animationState.update(delta);
this.animationState.apply(this.skeleton);
this.skeleton.updateWorldTransform();
}
this.skeleton.updateWorldTransform();
let viewportSize = this.scale(this.config.viewport.width, this.config.viewport.height, this.canvas.width, this.canvas.height);
this.sceneRenderer.camera.zoom = this.config.viewport.width / viewportSize.x;
@ -720,12 +734,6 @@
}
// Setup the animations after viewport, so default bounds don't get messed up.
if (!this.config.animation) {
if (skeletonData.animations.length > 0) {
this.config.animation = skeletonData.animations[0].name;
}
}
if (this.config.animations && this.config.animations.length > 0) {
this.config.animations.forEach(animation => {
if (!this.skeleton.data.findAnimation(animation)) {
@ -733,6 +741,16 @@
return;
}
});
if (!this.config.animation) {
this.config.animation = this.config.animations[0];
}
}
if (!this.config.animation) {
if (skeletonData.animations.length > 0) {
this.config.animation = skeletonData.animations[0].name;
}
}
if(this.config.animation) {
@ -755,6 +773,10 @@
// Setup the input processor and controllable bones
this.setupInput();
// Hide skin and animation if there's only the default skin / no animation
if (skeletonData.skins.length == 1) this.skinButton.classList.add("spine-player-hidden");
if (skeletonData.animations.length == 1) this.animationButton.classList.add("spine-player-hidden");
this.config.success(this);
this.loaded = true;
}
@ -780,9 +802,11 @@
target = bone;
}
}
handleHover();
},
up: (x, y) => {
target = null;
handleHover();
},
dragged: (x, y) => {
if (target != null) {
@ -796,6 +820,7 @@
target.y = coords.y - skeleton.y;
}
}
handleHover();
},
moved: (x, y) => {
for (var i = 0; i < controlBones.length; i++) {
@ -808,8 +833,42 @@
selectedBones[i] = null;
}
}
handleHover();
}
});
// For the manual hover to work, we need to disable
// hidding the controls if the mouse/touch entered
// the clickable area of a child of the controls
let mouseOverChildren = false;
canvas.onmouseover = (ev) => {
mouseOverChildren = false;
}
canvas.onmouseout = (ev) => {
if (ev.relatedTarget == null) {
mouseOverChildren = false;
} else {
mouseOverChildren = isContained(this.dom, (ev.relatedTarget as any));
}
}
let cancelId = 0;
let handleHover = () => {
if (!this.config.showControls) return;
clearTimeout(cancelId);
this.playerControls.classList.remove("hidden");
this.playerControls.classList.add("visible");
let remove = () => {
let popup = findWithClass(this.dom, "spine-player-popup");
if (popup.length == 0 && !mouseOverChildren) {
this.playerControls.classList.remove("visible");
this.playerControls.classList.add("hidden");
} else {
cancelId = setTimeout(remove, 1000);
}
};
cancelId = setTimeout(remove, 1000);
}
}
private play () {