hi. thanks for your answer.
I didn't use background color in css.
//stretchman.js
var stretchymanDemo = function (canvas, bgColor) {
var COLOR_INNER = new spine.Color(0.8, 0, 0, 0.5);
var COLOR_OUTER = new spine.Color(0.8, 0, 0, 0.8);
var COLOR_INNER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.5);
var COLOR_OUTER_SELECTED = new spine.Color(0.0, 0, 0.8, 0.8);
var canvas, gl, renderer, input, assetManager;
var skeleton, bounds, state;
var timeKeeper;
var target = null;
var hoverTargets = [];
var controlBones = [
"back leg controller",
"front leg controller",
"back arm controller",
"front arm controller",
"head controller",
"hip controller"
];
var coords = new spine.Vector3(), temp = new spine.Vector3(), temp2 = new spine.Vector2(), temp3 = new spine.Vector3();
var kneePos = new spine.Vector2();
var playButton, timeLine, spacing, isPlaying = true, playTime = 0;
if (!bgColor) bgColor = new spine.Color(255 / 255, 255 / 255, 255 / 255, 0.0);
function init() {
gl = canvas.context.gl;
renderer = new spine.SceneRenderer(canvas, gl);
assetManager = new spine.AssetManager(gl, spineDemos.path, spineDemos.downloader);
assetManager.loadTextureAtlas("atlas2.atlas");
assetManager.loadJson("demos.json");
timeKeeper = new spine.TimeKeeper();
input = new spine.Input(canvas);
}
function loadingComplete() {
var atlasLoader = new spine.AtlasAttachmentLoader(assetManager.get("atlas2.atlas"));
var skeletonJson = new spine.SkeletonJson(atlasLoader);
var skeletonData = skeletonJson.readSkeletonData(assetManager.get("demos.json").stretchyman);
skeleton = new spine.Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
var offset = new spine.Vector2();
bounds = new spine.Vector2();
skeleton.getBounds(offset, bounds, []);
for (var i = 0; i < controlBones.length; i++) hoverTargets.push(null);
state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
state.setAnimation(0, "idle", true);
renderer.camera.position.x = offset.x + bounds.x / 2;
renderer.camera.position.y = offset.y + bounds.y / 2;
renderer.skeletonDebugRenderer.drawMeshHull = false;
renderer.skeletonDebugRenderer.drawMeshTriangles = false;
setupUI();
setupInput();
}
function setupUI() {
var checkbox = $("#stretchyman-drawbones");
renderer.skeletonDebugRenderer.drawPaths = false;
renderer.skeletonDebugRenderer.drawBones = false;
checkbox.change(function () {
renderer.skeletonDebugRenderer.drawPaths = this.checked;
renderer.skeletonDebugRenderer.drawBones = this.checked;
});
}
function setupInput() {
input.addListener({
down: function (x, y) {
target = spineDemos.closest(canvas, renderer, skeleton, controlBones, hoverTargets, x, y);
},
up: function (x, y) {
target = null;
},
dragged: function (x, y) {
spineDemos.dragged(canvas, renderer, target, x, y);
if (target && target.data.name === "head controller") {
var hipControl = skeleton.findBone("hip controller");
target.x = spine.MathUtils.clamp(target.x, -65, 65);
target.y = Math.max(260, target.y);
}
},
moved: function (x, y) {
spineDemos.closest(canvas, renderer, skeleton, controlBones, hoverTargets, x, y);
}
});
}
function center(middleBone, hipBone, footBone, amount, dir) {
temp.set(footBone.worldX + skeleton.x, footBone.worldY + skeleton.y, 0)
.sub(temp3.set(hipBone.worldX + skeleton.x, hipBone.worldY + skeleton.y, 0));
var dist = Math.sqrt(temp.x * temp.x + temp.y * temp.y);
temp3.set(hipBone.worldX + skeleton.x, hipBone.worldY + skeleton.y, 0);
temp.scale(0.5).add(temp3);
middleBone.parent.worldToLocal(kneePos.set(temp.x, temp.y));
middleBone.x = kneePos.x;
middleBone.y = kneePos.y;
middleBone.children[0].y = (22 + Math.max(0, amount - dist * 0.3)) * dir;
}
function rotate(handBone, elbowBone) {
// can do all this in world space cause handBone is essentially in world space
var v = coords.set(handBone.worldX, handBone.worldY, 0).sub(new spine.Vector3(elbowBone.worldX, elbowBone.worldY, 0)).normalize();
var angle = Math.acos(v.x) * spine.MathUtils.radiansToDegrees + 180;
if (v.y < 0) angle = 360 - angle;
handBone.rotation = angle;
}
function render() {
timeKeeper.update();
var delta = timeKeeper.delta;
state.update(delta);
state.apply(skeleton);
center(skeleton.findBone("back leg middle"), skeleton.findBone("back leg 1"), skeleton.findBone("back leg controller"), 65, 1);
center(skeleton.findBone("front leg middle"), skeleton.findBone("front leg 1"), skeleton.findBone("front leg controller"), 65, 1);
center(skeleton.findBone("front arm middle"), skeleton.findBone("front arm 1"), skeleton.findBone("front arm controller"), 90, -1);
center(skeleton.findBone("back arm middle"), skeleton.findBone("back arm 1"), skeleton.findBone("back arm controller"), 90, -1);
rotate(skeleton.findBone("front arm controller"), skeleton.findBone("front arm elbow"));
rotate(skeleton.findBone("back arm controller"), skeleton.findBone("back arm elbow"));
var headControl = skeleton.findBone("head controller"), hipControl = skeleton.findBone("hip controller")
var head = skeleton.findBone("head");
var angle = Math.atan2(headControl.worldY - hipControl.worldY, headControl.worldX - hipControl.worldX) * spine.MathUtils.radDeg;
angle = (angle - 90) * 2.5;
head.rotation = head.data.rotation + Math.min(90, Math.abs(angle)) * Math.sign(angle);
skeleton.updateWorldTransform();
renderer.camera.viewportWidth = bounds.x * 1.2;
renderer.camera.viewportHeight = bounds.y * 1.5;
renderer.resize(spine.ResizeMode.Fit);
gl.clearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
gl.clear(gl.COLOR_BUFFER_BIT);
renderer.begin();
renderer.drawSkeleton(skeleton, true);
renderer.drawSkeletonDebug(skeleton, false, ["root"]);
gl.lineWidth(2);
for (var i = 0; i < controlBones.length; i++) {
console.log(controlBones.length);
var bone = skeleton.findBone(controlBones[i]);
var colorInner = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_INNER : spineDemos.NON_HOVER_COLOR_INNER;
var colorOuter = hoverTargets[i] !== null ? spineDemos.HOVER_COLOR_OUTER : spineDemos.NON_HOVER_COLOR_OUTER;
renderer.circle(true, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorInner);
renderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);
}
renderer.end();
gl.lineWidth(1);
}
init();
stretchymanDemo.assetManager = assetManager;
stretchymanDemo.loadingComplete = loadingComplete;
stretchymanDemo.render = render;
};
//utils.js
var spineDemos = {
HOVER_COLOR_INNER: new spine.Color(0, 0, 0, 0.25),
HOVER_COLOR_OUTER: new spine.Color(1, 1, 1, 1),
NON_HOVER_COLOR_INNER: new spine.Color(0, 0, 0, 0.5),
NON_HOVER_COLOR_OUTER: new spine.Color(0, 0, 0, 0.8),
demos: [],
loopRunning: false,
canvases: [],
downloader: new spine.Downloader(),
path: "assets/"
};
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1)
alert('Script Error: See Browser Console for Detail');
else {
var message = [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
alert(message);
}
return false;
};
(function () {
var timeKeeper = new spine.TimeKeeper();
function loop() {
timeKeeper.update();
if (spineDemos.log) console.log(timeKeeper.delta + ", " + timeKeeper.framesPerSecond);
requestAnimationFrame(loop);
var demos = spineDemos.demos;
for (var i = 0; i < demos.length; i++) {
var demo = demos[i];
checkElementVisible(demo);
renderDemo(demo);
}
}
function renderDemo(demo) {
if (demo.visible) {
var canvas = demo.canvas;
if (canvas.parentElement != demo.placeholder) {
$(canvas).detach();
demo.placeholder.appendChild(canvas);
}
let complete = demo.assetManager.isLoadingComplete();
if (complete) {
if (!demo.loaded) {
demo.loaded = true;
demo.loadingComplete();
}
if (spineDemos.log) console.log("Rendering: " + canvas.id);
demo.render();
}
demo.loadingScreen.draw(complete);
}
}
function checkElementVisible(demo) {
const rect = demo.placeholder.getBoundingClientRect();
const windowHeight = (window.innerHeight || document.documentElement.clientHeight);
const windowWidth = (window.innerWidth || document.documentElement.clientWidth);
const vertInView = (rect.top <= windowHeight * 1.1) && ((rect.top + rect.height) >= windowHeight * -0.1);
const horInView = (rect.left <= windowWidth * 1.1) && ((rect.left + rect.width) >= windowWidth * -0.1);
demo.visible = (vertInView && horInView);
}
function createCanvases(numCanvases) {
for (var i = 0; i < numCanvases; i++) {
var canvas = document.createElement("canvas");
canvas.width = 1; canvas.height = 1;
canvas.context = new spine.ManagedWebGLRenderingContext(canvas, { alpha: ture });
canvas.id = "canvas-" + i;
spineDemos.canvases.push(canvas);
}
}
spineDemos.init = function () {
var numCanvases = 5;
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") > -1;
if (isFirefox && isAndroid) numCanvases = 2;
createCanvases(numCanvases);
loadSliders();
requestAnimationFrame(loop);
}
spineDemos.addDemo = function (demo, placeholder) {
var canvas = spineDemos.canvases[spineDemos.demos.length % spineDemos.canvases.length];
demo(canvas);
demo.placeholder = placeholder;
demo.canvas = canvas;
demo.visible = false;
var renderer = new spine.SceneRenderer(canvas, canvas.context.gl);
demo.loadingScreen = new spine.LoadingScreen(renderer);
$(window).on('DOMContentLoaded load resize scroll', function () {
checkElementVisible(demo);
renderDemo(demo);
});
checkElementVisible(demo);
spineDemos.demos.push(demo);
}
var coords = new spine.Vector3();
var mouse = new spine.Vector3();
spineDemos.closest = function (canvas, renderer, skeleton, controlBones, hoverTargets, x, y) {
mouse.set(x, canvas.clientHeight - y, 0)
var bestDistance = 24, index = 0;
var best;
for (var i = 0; i < controlBones.length; i++) {
hoverTargets[i] = null;
let bone = skeleton.findBone(controlBones[i]);
let distance = renderer.camera.worldToScreen(
coords.set(bone.worldX, bone.worldY, 0),
canvas.clientWidth, canvas.clientHeight).distance(mouse);
if (distance < bestDistance) {
bestDistance = distance;
best = bone;
index = i;
}
}
if (best) hoverTargets[index] = best;
return best;
};
var position = new spine.Vector3();
spineDemos.dragged = function (canvas, renderer, target, x, y) {
if (target) {
x = spine.MathUtils.clamp(x, 0, canvas.clientWidth)
y = spine.MathUtils.clamp(y, 0, canvas.clientHeight);
renderer.camera.screenToWorld(coords.set(x, y, 0), canvas.clientWidth, canvas.clientHeight);
if (target.parent !== null) {
target.parent.worldToLocal(position.set(coords.x, coords.y));
target.x = position.x;
target.y = position.y;
} else {
target.x = coords.x;
target.y = coords.y;
}
}
};
})();
//demos.css
body, html {
margin: 0;
font-family: Tahoma;
font-size: 11pt;
}
body {
padding: 15px;
}
br {
display: block;
content: "";
margin-top: 15px;
}
h2 {
padding-top: 1em;
}
canvas {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
}
.aspect {
position: relative;
width: 100%;
}
.standalone {
width: 797px;
height: 1064px;
}
.demo {
clear: both;
}
.demo-container {
float: left;
width: 58%;
}
.demo-text {
float: left;
width: 38%;
margin-left: 2%;
margin-right: 2%;
}
.timeline, .timeline td:nth-child(2) {
width: 100%;
}
.play {
background: black;
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath%20fill%3D%27%23F2F2F2%27%20d%3D%27M30.185%2C15.5L12.556%2C24.8V6.201L30.185%2C15.5z%27%2F%3E%3C%2Fsvg%3E");
width: 40px;
height: 30px;
}
.pause {
background: black;
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath%20fill%3D%22%23F2F2F2%22%20d%3D%22M26.94%2C6.978v17.045h-5.249V6.978H26.94z%22%2F%3E%3Cpath%20fill%3D%22%23F2F2F2%22%20d%3D%22M18.975%2C6.978v17.045h-5.249V6.978H18.975z%22%2F%3E%3C%2Fsvg%3E");
width: 40px;
height: 30px;
margin: 0;
}
.checkbox {
display: inline;
}
.slider {
width: 100%;
max-width: 800px;
border-radius: 3px;
text-align: left;
transform: translateZ(0);
background: #222;
display: inline-block;
}
.slider, .slider.filled span {
height: 15px;
border: 1px solid #c5c5c5;
}
.slider div {
position: absolute;
top: -2px;
width: 10px;
height: 17px;
background: white;
border: #000 1px solid;
border-radius: 2px;
z-index: 10;
}
.slider.filled {
border: 0;
}
.slider.filled div {
top: -1px;
margin-left: 1px;
}
.slider.filled span {
display: block;
position: absolute;
background: #3ea9f5;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
z-index: 5;
}
.slider.filled span:last-child {
background: #222;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.overlay {
opacity: 1;
transition: opacity 0.5s ease;
z-index: 10;
}
.overlay-hide {
opacity: 0;
}
.overlay-label {
display: none;
}
//stretchyman.html
<html>
<meta charset="UTF-8">
<title>Strechyman - Spine Demo</title>
<link rel="stylesheet" href="demos.css">
<script src="https://unpkg.com/@esotericsoftware/spine-webgl@4.0.*/dist/iife/spine-webgl.js"></script>
<!
---
<script src="../dist/iife/spine-webgl.js"></script>
---
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script src="utils.js"></script>
<script src="stretchyman.js"></script>
<body>
<center>
<div class="aspect standalone"></div>
<input id="stretchyman-drawbones" type="checkbox"></input> Display bones
</center>
<script>
spineDemos.init();
spineDemos.addDemo(stretchymanDemo, document.getElementsByClassName("aspect")[0]);
</script>
</body>
</html>