import { __awaiter } from "tslib"; import { PromiseQueue } from "./PromiseQueue"; import { ROTATE_DIRECTION, ZOOM_ACTION, } from "./types"; import { buildKrpanoAction, buildKrpanoTagSetterActions } from "./utils"; export class KrpanoActionProxy { constructor(krpanoRenderer, name = "ReactKrpanoActionProxy") { this.eventHandlers = []; this.syncTagsLoaded = false; this.syncTagStack = []; this.krpanoRenderer = krpanoRenderer; this.name = name; // krpano 1.19 版本不支持动态插入 include,只能在文本中插入后重新加载 this.dynamicTagWaitQueue = new PromiseQueue(); } /** * 等待 include 标签加载完成 */ waitIncludeLoaded(push) { return this.syncTagsLoaded ? Promise.resolve() : // 先进后出 this.dynamicTagWaitQueue[push ? "push" : "unshift"](); } /** * 执行 Javascript 函数 * @param action 动作 * @param nexttick 是否在下一个渲染帧后执行 */ call(action, nexttick = false) { var _a; const actionStr = nexttick ? `nexttick(${action})` : action; (_a = this.krpanoRenderer) === null || _a === void 0 ? void 0 : _a.call(actionStr); } set(name, ...params) { this.call(buildKrpanoAction("set", name, ...params)); } /** * 动态添加标签 * @param tag 标签 * @param name 名称 * @param attrs 属性 */ setTag(tag, name, attrs) { return __awaiter(this, void 0, void 0, function* () { let nexttick = false; if (tag === "hotspot" || tag === "events") { nexttick = true; } yield this.waitIncludeLoaded(); this.call(buildKrpanoTagSetterActions(name ? `${tag}[${name}]` : tag, attrs), nexttick); }); } get(name) { var _a; return (_a = this.krpanoRenderer) === null || _a === void 0 ? void 0 : _a.get(name); } /** * 删除场景 * @param name 场景名称 */ removeScene(name) { if (this.get("scene") && typeof this.get("scene").removeItem === "function") { this.get("scene").removeItem(name); } else { // TODO: report Error } } /** * 加载场景 * @param name 场景 name */ loadScene(name) { this.call(buildKrpanoAction("loadscene", name, "null", "MERGE", "BLEND(0.5)")); } /** * 旋转视图 * @param direction 方位 * @param degrees 旋转度数,默认为 10 */ rotateView(direction, degrees = 10) { let str = ""; const view = this.get("view"); switch (direction) { case ROTATE_DIRECTION.LEFT: str = `view.hlookat, ${(view.hlookat || 0) - degrees}`; break; case ROTATE_DIRECTION.RIGHT: str = `view.hlookat, ${(view.hlookat || 0) + degrees}`; break; case ROTATE_DIRECTION.UP: str = `view.vlookat, ${(view.vlookat || 0) - degrees}`; break; case ROTATE_DIRECTION.DOWN: str = `view.vlookat, ${(view.vlookat || 0) + degrees}`; break; } this.call(buildKrpanoAction("tween", str, 0.5)); } /** * 缩放视图 * @param action 动作 * @param num 缩放大小 */ zoomView(action, num = 10) { const view = this.get("view"); const targetFov = action === ZOOM_ACTION.IN ? -num : num; this.call(buildKrpanoAction("tween", "view.fov", (view.fov || 0) + targetFov, 1)); } on(eventName, selector, handler) { this.eventHandlers.push({ eventName: eventName.toLowerCase(), selector, handler, }); return this; } off(eventName, selector, handler) { this.eventHandlers = this.eventHandlers.filter((e) => !(e.eventName === eventName.toLowerCase() && e.selector === selector && e.handler === handler)); } fire(eventName, selector) { this.eventHandlers .filter((e) => e.eventName === eventName.toLowerCase() && e.selector === selector) .map(({ handler }) => handler(this)); } bindEvents(selector, mapEventsToHandler) { Object.keys(mapEventsToHandler).map((eventName) => { const func = mapEventsToHandler[eventName]; if (func) { this.on(eventName, selector, func); } }); } unbindEvents(selector, mapEventsToHandler) { Object.keys(mapEventsToHandler).map((eventName) => { const func = mapEventsToHandler[eventName]; if (func) { this.off(eventName, selector, func); } }); } addHotspot(name, attrs) { return __awaiter(this, void 0, void 0, function* () { yield this.waitIncludeLoaded(); this.call(buildKrpanoAction("addhotspot", name), true); this.setTag("hotspot", name, attrs); }); } removeHotspot(name) { this.call(buildKrpanoAction("removehotspot", name), true); } pushSyncTag(tagName, attribute) { this.syncTagStack.unshift({ tagName, attribute, }); } createSyncTags() { return __awaiter(this, void 0, void 0, function* () { const xmlDoc = yield this.getXMLContent(); const krpanoElement = xmlDoc.querySelector("krpano"); while (this.syncTagStack.length) { const tag = this.syncTagStack.pop(); const element = xmlDoc.createElement(tag.tagName); for (const key in tag.attribute) { element.setAttribute(key, tag.attribute[key]); } krpanoElement === null || krpanoElement === void 0 ? void 0 : krpanoElement.insertBefore(element, null); } return xmlDoc; }); } getXMLContent() { return __awaiter(this, void 0, void 0, function* () { let contentText = ""; const xml = this === null || this === void 0 ? void 0 : this.get("xml"); const parser = new DOMParser(); if (xml.content) { contentText = xml.content; } else if (xml.url) { contentText = yield fetch(xml.url).then((res) => res.text()); } return parser.parseFromString(contentText, "text/xml"); }); } }