@tomiaa/live2d
Version:
开箱即用的 Live2d
169 lines (168 loc) • 10.8 kB
JavaScript
import './style.css';
var f = Object.defineProperty;
var y = (l, i, t) => i in l ? f(l, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[i] = t;
var o = (l, i, t) => (y(l, typeof i != "symbol" ? i + "" : i, t), t);
import { Hitokoto as x } from "@tomiaa/hitokoto";
import { createNamespacs as I, drag as P, loadAsyncJs as h, randomInteger as C } from "@tomiaa/utils";
import { Live2d_3_ModelList as M, Live2dModelList as S } from "./modelList.js";
import "./index.scss.js";
const r = I("live2d"), _ = '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" ><path fill="currentColor" d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"></path></svg>', b = '<svg width="30" height="30" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M42 19H5.99998" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> <path d="M30 7L42 19" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> <path d="M6.79897 29H42.799" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> <path d="M6.79895 29L18.799 41" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> </svg>', H = '<svg width="30" height="30" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" > <path fill-rule="evenodd" clip-rule="evenodd" d="M20.7301 27.1255C22.7185 25.833 25.2815 25.833 27.2699 27.1255L42.8202 37.2331C43.556 37.7114 44 38.5295 44 39.4071C44 40.8391 42.8391 42 41.4071 42H6.59288C5.16087 42 4 40.8391 4 39.4071C4 38.5295 4.44395 37.7114 5.17979 37.2331L20.7301 27.1255Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> <path d="M24 25C24 25 30 16.3137 30 13C30 9.68629 27.3137 7 24 7C20.6863 7 18 9.68629 18 13" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" /> </svg>';
class E {
constructor(i) {
o(this, "options", {
el: "#live2d",
loadLive2d_2: !0,
loadLive2d_3: !0,
playLoadingAnimation: !0,
showLoading: !0,
showControl: !0,
iApplicationOptions: {},
maxWidth: 400,
minWidth: 200,
aspectRatio: [10, 9],
randomPeople: !0,
allowDrag: !0,
hitokoto: !0
});
o(this, "el");
o(this, "canvas");
o(this, "Live2DModel");
o(this, "app");
o(this, "loading", !1);
o(this, "model");
o(this, "modelList", []);
o(this, "currentModelOption");
o(this, "personIndex", 0);
o(this, "clothingIndex", 0);
o(this, "elLoading");
o(this, "elControl");
o(this, "elSwitchPerson");
o(this, "elSwitchClothing");
o(this, "elHitokoto");
o(this, "hitokoto");
Object.assign(this.options, i);
const { el: t } = this.options;
typeof t == "string" ? this.el = document.querySelector(t) : this.el = t, this.el.classList.add(r.b()), this.init();
}
get getJsBaseURL() {
return this.options.jsBaseURL || "https://tomiaa12.github.io/live2d/public";
}
get getLive2d_2_ModelBaseURL() {
return this.options.live2d_2_ModelBaseURL || this.getJsBaseURL;
}
get getLive2d_3_ModelBaseURL() {
return this.options.live2d_2_ModelBaseURL || this.getJsBaseURL;
}
async init() {
var i, t, s, e;
await ((t = (i = this.options).beforeInit) == null ? void 0 : t.call(i, {
options: this.options,
modelList: this.modelList
})), this.options.allowDrag && P({ el: this.el }), await this.loadJS(), this.createPIXI(), await this.loadModelList(), this.addLoadingSvg(), this.addControls(), this.setPersonIndex(), await this.loadModel(), window.addEventListener("resize", this.onresize.bind(this)), this.createHitokoto(), (e = (s = this.options).afterInit) == null || e.call(s, {
options: this.options,
modelList: this.modelList,
currentModelOption: this.currentModelOption,
Live2DModel: this.Live2DModel,
app: this.app
});
}
async loadJS() {
await Promise.all([
h(this.getJsBaseURL + "/js/pixi.min.js"),
h(this.getJsBaseURL + "/js/live2d.min.js"),
h(this.getJsBaseURL + "/js/live2dcubismcore.min.js")
]), await h(this.getJsBaseURL + "/js/index.min.js"), this.Live2DModel = window.PIXI.live2d.Live2DModel;
}
createPIXI() {
this.canvas || (this.canvas = document.createElement("canvas"), this.el.appendChild(this.canvas), this.canvas.addEventListener("click", this.animation.bind(this))), this.app = new window.PIXI.Application({
view: this.canvas,
width: 400,
height: 300,
backgroundAlpha: 0,
...this.options.iApplicationOptions
});
}
async loadModelList() {
if (!this.options.loadLive2d_2 && !this.options.loadLive2d_3)
return console.error("loadLive2d_2与loadLive2d_3至少加载一种!"), Promise.reject();
this.options.loadLive2d_3 && (this.modelList = [...this.modelList, ...M]), this.options.loadLive2d_2 && (this.modelList = [...this.modelList, ...S]);
}
addLoadingSvg() {
this.options.showLoading && (this.elLoading = document.createElement("i"), this.elLoading.innerHTML = _, this.elLoading.classList.add(r.e("loading")), this.el.appendChild(this.elLoading));
}
addControls() {
this.options.showControl && (this.elControl = document.createElement("div"), this.elControl.classList.add(r.e("control")), this.elSwitchPerson = document.createElement("i"), this.elSwitchPerson.innerHTML = b, this.elSwitchPerson.setAttribute("data-tip", "切换人物"), this.elSwitchPerson.addEventListener("click", this.switchPerson.bind(this)), this.elControl.appendChild(this.elSwitchPerson), this.elSwitchClothing = document.createElement("i"), this.elSwitchClothing.innerHTML = H, this.elSwitchClothing.setAttribute("data-tip", "更换服装"), this.elSwitchClothing.addEventListener(
"click",
this.switchClothing.bind(this)
), this.elControl.appendChild(this.elSwitchClothing), this.el.appendChild(this.elControl));
}
async loadModel() {
var t, s, e;
this.loading = !0, this.el.style.pointerEvents = "none", this.elLoading && (this.elLoading.style.display = "block"), this.elControl && (this.elControl.style.display = "none"), this.elHitokoto && (this.elHitokoto.style.display = "none", (t = this.hitokoto) == null || t.getData()), (e = (s = this.model) == null ? void 0 : s.destroy) == null || e.call(s);
const i = this.currentModelOption.version === 3 ? this.getLive2d_3_ModelBaseURL : this.getLive2d_2_ModelBaseURL;
try {
this.model = await this.Live2DModel.from(
i + this.currentModelOption.list[this.clothingIndex]
);
} catch {
this.elLoading && (this.elLoading.style.display = "none");
}
this.loading = !1, this.el.style.pointerEvents = "auto", this.elLoading && (this.elLoading.style.display = "none"), this.elControl && (this.elControl.style.display = "block"), this.elHitokoto && (this.elHitokoto.style.display = "block"), this.app.stage.addChild(this.model), this.onresize(), this.options.playLoadingAnimation && this.animation("login");
}
setPersonIndex() {
this.options.randomPeople ? this.personIndex = C(0, this.modelList.length - 1) : ++this.personIndex >= this.modelList.length && (this.personIndex = 0), this.currentModelOption = this.modelList[this.personIndex], this.elSwitchClothing.style.display = this.currentModelOption.list.length > 1 ? "block" : "none";
}
onresize() {
var p, g, L, w, m, v, k, u;
const i = this.model;
if (!i)
return;
const t = this.currentModelOption, s = this.app;
let e = window.innerWidth * 0.3;
e > this.options.maxWidth && (e = this.options.maxWidth), e < this.options.minWidth && (e = this.options.minWidth);
const n = e / (((p = t == null ? void 0 : t.aspectRatio) == null ? void 0 : p[0]) || this.options.aspectRatio[0]) * (((g = t == null ? void 0 : t.aspectRatio) == null ? void 0 : g[1]) || this.options.aspectRatio[1]);
s.view.style.width = e + "px", s.view.style.height = n + "px", s.renderer.resize(e, n);
const c = i.width > i.height ? e / i.width : n / i.height;
i.width *= c, i.height *= c;
let a, d;
typeof (t == null ? void 0 : t.scale) == "number" ? a = d = t == null ? void 0 : t.scale : (a = (L = t == null ? void 0 : t.scale) == null ? void 0 : L.x, d = (w = t == null ? void 0 : t.scale) == null ? void 0 : w.y), i.width *= ((m = t == null ? void 0 : t.stretch) == null ? void 0 : m.width) || 1, i.height *= ((v = t == null ? void 0 : t.stretch) == null ? void 0 : v.height) || 1, i.scale = new window.PIXI.Point(
i.scale.x * (a || 1),
i.scale.y * (d || 1)
), i.position = new window.PIXI.Point(
e - i.width + (((k = t == null ? void 0 : t.position) == null ? void 0 : k.x) || 0),
n - i.height + (((u = t == null ? void 0 : t.position) == null ? void 0 : u.y) || 0)
);
}
animation(i) {
const t = this.model;
if (typeof i == "string") {
t.motion(i);
return;
}
const [s] = t.hitTest((i == null ? void 0 : i.offsetX) || 0, (i == null ? void 0 : i.offsetY) || 0), e = Object.keys(
t.internalModel.motionManager.definitions
).filter((n) => n !== "login");
s ? t.motion(e.filter((n) => n.includes(s))[0]) : t.motion(e[C(0, e.length - 1)]);
}
switchPerson() {
event == null || event.stopPropagation(), this.clothingIndex = 0, this.setPersonIndex(), this.loadModel();
}
switchClothing() {
event == null || event.stopPropagation(), ++this.clothingIndex >= this.currentModelOption.list.length && (this.clothingIndex = 0), this.loadModel();
}
createHitokoto() {
this.options.hitokoto && (this.elHitokoto = document.createElement("div"), this.el.appendChild(this.elHitokoto), this.elHitokoto.addEventListener("mousedown", (i) => {
i.stopPropagation();
}), this.hitokoto = new x({
el: this.elHitokoto,
...this.options.hitokotoOptions
}));
}
destroy() {
window.removeEventListener("resize", this.onresize), this.el.innerHTML = "";
}
}
export {
E as Live2d,
E as default
};