KrpanoActionProxy.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { __awaiter } from "tslib";
  2. import { PromiseQueue } from "./PromiseQueue";
  3. import { ROTATE_DIRECTION, ZOOM_ACTION, } from "./types";
  4. import { buildKrpanoAction, buildKrpanoTagSetterActions } from "./utils";
  5. export class KrpanoActionProxy {
  6. constructor(krpanoRenderer, name = "ReactKrpanoActionProxy") {
  7. this.eventHandlers = [];
  8. this.syncTagsLoaded = false;
  9. this.syncTagStack = [];
  10. this.krpanoRenderer = krpanoRenderer;
  11. this.name = name;
  12. // krpano 1.19 版本不支持动态插入 include,只能在文本中插入后重新加载
  13. this.dynamicTagWaitQueue = new PromiseQueue();
  14. }
  15. /**
  16. * 等待 include 标签加载完成
  17. */
  18. waitIncludeLoaded(push) {
  19. return this.syncTagsLoaded
  20. ? Promise.resolve()
  21. : // 先进后出
  22. this.dynamicTagWaitQueue[push ? "push" : "unshift"]();
  23. }
  24. /**
  25. * 执行 Javascript 函数
  26. * @param action 动作
  27. * @param nexttick 是否在下一个渲染帧后执行
  28. */
  29. call(action, nexttick = false) {
  30. var _a;
  31. const actionStr = nexttick ? `nexttick(${action})` : action;
  32. (_a = this.krpanoRenderer) === null || _a === void 0 ? void 0 : _a.call(actionStr);
  33. }
  34. set(name, ...params) {
  35. this.call(buildKrpanoAction("set", name, ...params));
  36. }
  37. /**
  38. * 动态添加标签
  39. * @param tag 标签
  40. * @param name 名称
  41. * @param attrs 属性
  42. */
  43. setTag(tag, name, attrs) {
  44. return __awaiter(this, void 0, void 0, function* () {
  45. let nexttick = false;
  46. if (tag === "hotspot" || tag === "events") {
  47. nexttick = true;
  48. }
  49. yield this.waitIncludeLoaded();
  50. this.call(buildKrpanoTagSetterActions(name ? `${tag}[${name}]` : tag, attrs), nexttick);
  51. });
  52. }
  53. get(name) {
  54. var _a;
  55. return (_a = this.krpanoRenderer) === null || _a === void 0 ? void 0 : _a.get(name);
  56. }
  57. /**
  58. * 删除场景
  59. * @param name 场景名称
  60. */
  61. removeScene(name) {
  62. if (this.get("scene") &&
  63. typeof this.get("scene").removeItem === "function") {
  64. this.get("scene").removeItem(name);
  65. }
  66. else {
  67. // TODO: report Error
  68. }
  69. }
  70. /**
  71. * 加载场景
  72. * @param name 场景 name
  73. */
  74. loadScene(name) {
  75. this.call(buildKrpanoAction("loadscene", name, "null", "MERGE", "BLEND(0.5)"));
  76. }
  77. /**
  78. * 旋转视图
  79. * @param direction 方位
  80. * @param degrees 旋转度数,默认为 10
  81. */
  82. rotateView(direction, degrees = 10) {
  83. let str = "";
  84. const view = this.get("view");
  85. switch (direction) {
  86. case ROTATE_DIRECTION.LEFT:
  87. str = `view.hlookat, ${(view.hlookat || 0) - degrees}`;
  88. break;
  89. case ROTATE_DIRECTION.RIGHT:
  90. str = `view.hlookat, ${(view.hlookat || 0) + degrees}`;
  91. break;
  92. case ROTATE_DIRECTION.UP:
  93. str = `view.vlookat, ${(view.vlookat || 0) - degrees}`;
  94. break;
  95. case ROTATE_DIRECTION.DOWN:
  96. str = `view.vlookat, ${(view.vlookat || 0) + degrees}`;
  97. break;
  98. }
  99. this.call(buildKrpanoAction("tween", str, 0.5));
  100. }
  101. /**
  102. * 缩放视图
  103. * @param action 动作
  104. * @param num 缩放大小
  105. */
  106. zoomView(action, num = 10) {
  107. const view = this.get("view");
  108. const targetFov = action === ZOOM_ACTION.IN ? -num : num;
  109. this.call(buildKrpanoAction("tween", "view.fov", (view.fov || 0) + targetFov, 1));
  110. }
  111. on(eventName, selector, handler) {
  112. this.eventHandlers.push({
  113. eventName: eventName.toLowerCase(),
  114. selector,
  115. handler,
  116. });
  117. return this;
  118. }
  119. off(eventName, selector, handler) {
  120. this.eventHandlers = this.eventHandlers.filter((e) => !(e.eventName === eventName.toLowerCase() &&
  121. e.selector === selector &&
  122. e.handler === handler));
  123. }
  124. fire(eventName, selector) {
  125. this.eventHandlers
  126. .filter((e) => e.eventName === eventName.toLowerCase() && e.selector === selector)
  127. .map(({ handler }) => handler(this));
  128. }
  129. bindEvents(selector, mapEventsToHandler) {
  130. Object.keys(mapEventsToHandler).map((eventName) => {
  131. const func = mapEventsToHandler[eventName];
  132. if (func) {
  133. this.on(eventName, selector, func);
  134. }
  135. });
  136. }
  137. unbindEvents(selector, mapEventsToHandler) {
  138. Object.keys(mapEventsToHandler).map((eventName) => {
  139. const func = mapEventsToHandler[eventName];
  140. if (func) {
  141. this.off(eventName, selector, func);
  142. }
  143. });
  144. }
  145. addHotspot(name, attrs) {
  146. return __awaiter(this, void 0, void 0, function* () {
  147. yield this.waitIncludeLoaded();
  148. this.call(buildKrpanoAction("addhotspot", name), true);
  149. this.setTag("hotspot", name, attrs);
  150. });
  151. }
  152. removeHotspot(name) {
  153. this.call(buildKrpanoAction("removehotspot", name), true);
  154. }
  155. pushSyncTag(tagName, attribute) {
  156. this.syncTagStack.unshift({
  157. tagName,
  158. attribute,
  159. });
  160. }
  161. createSyncTags() {
  162. return __awaiter(this, void 0, void 0, function* () {
  163. const xmlDoc = yield this.getXMLContent();
  164. const krpanoElement = xmlDoc.querySelector("krpano");
  165. while (this.syncTagStack.length) {
  166. const tag = this.syncTagStack.pop();
  167. const element = xmlDoc.createElement(tag.tagName);
  168. for (const key in tag.attribute) {
  169. element.setAttribute(key, tag.attribute[key]);
  170. }
  171. krpanoElement === null || krpanoElement === void 0 ? void 0 : krpanoElement.insertBefore(element, null);
  172. }
  173. return xmlDoc;
  174. });
  175. }
  176. getXMLContent() {
  177. return __awaiter(this, void 0, void 0, function* () {
  178. let contentText = "";
  179. const xml = this === null || this === void 0 ? void 0 : this.get("xml");
  180. const parser = new DOMParser();
  181. if (xml.content) {
  182. contentText = xml.content;
  183. }
  184. else if (xml.url) {
  185. contentText = yield fetch(xml.url).then((res) => res.text());
  186. }
  187. return parser.parseFromString(contentText, "text/xml");
  188. });
  189. }
  190. }