Bladeren bron

feat: add draggable_hotspot action

chenlei 1 jaar geleden
bovenliggende
commit
c61f7eba8a
4 gewijzigde bestanden met toevoegingen van 568 en 531 verwijderingen
  1. 160 160
      packages/docs/.umirc.ts
  2. 124 98
      packages/docs/docs/krpano/hotspot/index.md
  3. 200 193
      packages/krpano/src/components/Krpano.tsx
  4. 84 80
      packages/krpano/src/types.ts

+ 160 - 160
packages/docs/.umirc.ts

@@ -1,160 +1,160 @@
-import { defineConfig } from "dumi";
-import { join } from "path";
-
-export default defineConfig({
-  history: {
-    type: "hash",
-  },
-  title: "@dage/tools",
-  favicon: "https://4dkk.4dage.com/FDKKIMG/icon/kankan_icon.ico",
-  outputPath: "docs-dist",
-  mode: "site",
-  resolve: {
-    includes: ["./docs"],
-  },
-  headScripts: [
-    {
-      src: "https://houseoss.4dkankan.com/project/leifeng-transfer/krpano.js",
-    },
-  ],
-  alias: {
-    "@dage/hooks": join(__dirname, "../hooks/dist/"),
-    "@dage/utils": join(__dirname, "../utils/dist/"),
-    "@dage/service": join(__dirname, "../service/dist/"),
-    "@dage/pc-components": join(__dirname, "../pc-components/dist/"),
-    "@dage/krpano": join(__dirname, "../krpano/build/"),
-  },
-  navs: [
-    {
-      title: "组件",
-      path: "/components",
-    },
-    {
-      title: "工具",
-      path: "/utils",
-    },
-    {
-      title: "service",
-      path: "/service",
-    },
-    {
-      title: "krpano",
-      path: "/krpano",
-    },
-    {
-      title: "更新日志",
-      path: "/log",
-    },
-    {
-      title: "Gogs",
-      path: "http://face3d.4dage.com:7005/chenlei/dage-web-tools",
-    },
-  ],
-  menus: {
-    "/components": [
-      {
-        title: "获取用户信息",
-        path: "/components/login",
-      },
-      {
-        title: "布局",
-        children: ["/components/TableActions"],
-      },
-      {
-        title: "表单组件",
-        children: [
-          "/components/CheckboxGroup",
-          "/components/Upload",
-          "/components/FileCheckbox",
-          "/components/Map",
-          "/components/Editor",
-        ],
-      },
-      {
-        title: "反馈",
-        children: ["/components/Loading"],
-      },
-      {
-        title: "工具",
-        children: [
-          /**
-           * @deprecated 将控制权交给应用,使用 @dage/service
-           */
-          // "/components/utils/services",
-          "/components/utils/storage",
-        ],
-      },
-    ],
-    "/utils": [
-      {
-        title: "hooks",
-        path: "/utils/hooks",
-      },
-      {
-        title: "EventBus 事件",
-        path: "/utils/eventbus",
-      },
-      {
-        title: "日期格式化",
-        path: "/utils/date",
-      },
-      {
-        title: "string 方法",
-        path: "/utils/string",
-      },
-    ],
-    "/log": [
-      {
-        title: "pc-components 更新日志",
-        path: "/log/PC-COMPONENTS_CHANGELOG",
-      },
-      {
-        title: "backend-cli 更新日志",
-        path: "/log/BACKEND-CLI_CHANGELOG",
-      },
-      {
-        title: "utils 更新日志",
-        path: "/log/UTILS_CHANGELOG",
-      },
-      {
-        title: "service 更新日志",
-        path: "/log/SERVICE_CHANGELOG",
-      },
-      {
-        title: "krpano 更新日志",
-        path: "/log/KRPANO_CHANGELOG",
-      },
-    ],
-    "/krpano": [
-      {
-        title: "基本使用",
-        path: "/krpano",
-      },
-      {
-        title: "Scene 场景",
-        path: "/krpano/scene",
-      },
-      {
-        title: "HotSpot 热点",
-        path: "/krpano/hotspot",
-      },
-      {
-        title: "Autorotate 自动旋转",
-        path: "/krpano/autorotate",
-      },
-      {
-        title: "View 视角",
-        path: "/krpano/view",
-      },
-      {
-        title: "Events 事件",
-        path: "/krpano/events",
-      },
-      {
-        title: "Layer 图层",
-        path: "/krpano/layer",
-      },
-    ],
-  },
-  // more config: https://d.umijs.org/config
-});
+import { defineConfig } from "dumi";
+import { join } from "path";
+
+export default defineConfig({
+  history: {
+    type: "hash",
+  },
+  title: "@dage/tools",
+  favicon: "https://4dkk.4dage.com/FDKKIMG/icon/kankan_icon.ico",
+  outputPath: "docs-dist",
+  mode: "site",
+  resolve: {
+    includes: ["./docs"],
+  },
+  headScripts: [
+    {
+      src: "https://houseoss.4dkankan.com/project/leifeng-transfer/krpano.js",
+    },
+  ],
+  alias: {
+    "@dage/hooks": join(__dirname, "../hooks/dist/"),
+    "@dage/utils": join(__dirname, "../utils/dist/"),
+    "@dage/service": join(__dirname, "../service/dist/"),
+    "@dage/pc-components": join(__dirname, "../pc-components/dist/"),
+    "@dage/krpano": join(__dirname, "../krpano/build/"),
+  },
+  navs: [
+    {
+      title: "组件",
+      path: "/components",
+    },
+    {
+      title: "工具",
+      path: "/utils",
+    },
+    {
+      title: "service",
+      path: "/service",
+    },
+    {
+      title: "krpano",
+      path: "/krpano",
+    },
+    {
+      title: "更新日志",
+      path: "/log",
+    },
+    {
+      title: "Gogs",
+      path: "http://face3d.4dage.com:7005/chenlei/dage-web-tools",
+    },
+  ],
+  menus: {
+    "/components": [
+      {
+        title: "获取用户信息",
+        path: "/components/login",
+      },
+      {
+        title: "布局",
+        children: ["/components/TableActions"],
+      },
+      {
+        title: "表单组件",
+        children: [
+          "/components/CheckboxGroup",
+          "/components/Upload",
+          "/components/FileCheckbox",
+          "/components/Map",
+          "/components/Editor",
+        ],
+      },
+      {
+        title: "反馈",
+        children: ["/components/Loading"],
+      },
+      {
+        title: "工具",
+        children: [
+          /**
+           * @deprecated 将控制权交给应用,使用 @dage/service
+           */
+          // "/components/utils/services",
+          "/components/utils/storage",
+        ],
+      },
+    ],
+    "/utils": [
+      {
+        title: "hooks",
+        path: "/utils/hooks",
+      },
+      {
+        title: "EventBus 事件",
+        path: "/utils/eventbus",
+      },
+      {
+        title: "日期格式化",
+        path: "/utils/date",
+      },
+      {
+        title: "string 方法",
+        path: "/utils/string",
+      },
+    ],
+    "/log": [
+      {
+        title: "pc-components 更新日志",
+        path: "/log/PC-COMPONENTS_CHANGELOG",
+      },
+      {
+        title: "backend-cli 更新日志",
+        path: "/log/BACKEND-CLI_CHANGELOG",
+      },
+      {
+        title: "utils 更新日志",
+        path: "/log/UTILS_CHANGELOG",
+      },
+      {
+        title: "service 更新日志",
+        path: "/log/SERVICE_CHANGELOG",
+      },
+      {
+        title: "krpano 更新日志",
+        path: "/log/KRPANO_CHANGELOG",
+      },
+    ],
+    "/krpano": [
+      {
+        title: "基本使用",
+        path: "/krpano",
+      },
+      {
+        title: "Scene 场景",
+        path: "/krpano/scene",
+      },
+      {
+        title: "HotSpot 热点",
+        path: "/krpano/hotspot",
+      },
+      {
+        title: "Autorotate 自动旋转",
+        path: "/krpano/autorotate",
+      },
+      {
+        title: "View 视角",
+        path: "/krpano/view",
+      },
+      {
+        title: "Events 事件",
+        path: "/krpano/events",
+      },
+      {
+        title: "Layer 图层",
+        path: "/krpano/layer",
+      },
+    ],
+  },
+  // more config: https://d.umijs.org/config
+});

+ 124 - 98
packages/docs/docs/krpano/hotspot/index.md

@@ -1,98 +1,124 @@
-## 示例
-
-支持 `html`,但是在 vr 视角下仅支持文本和文本样式。
-
-```tsx
-import React, { useState, useMemo } from "react";
-import { HotSpot, Krpano, Scene, View } from "@dage/krpano";
-import "./index.css";
-
-const URL = "https://houseoss.4dkankan.com/project/leifeng-transfer";
-
-export default () => {
-  const [currentScene, setCurrentScene] = useState("center1");
-  const [hotspotHover, setHotspotHover] = useState(false);
-
-  const CENTER_SCENE_LIST = useMemo<SceneProps[]>(
-    () => [
-      {
-        name: "center1",
-        previewUrl: URL + "/panos/center1.tiles/preview.jpg",
-        imageTagAttributes: {
-          type: "cube",
-          tileSize: 512,
-          multires: true,
-        },
-        images: [
-          {
-            tiledImageWidth: 2624,
-            tiledImageHeight: 2624,
-            url: URL + "/panos/center1.tiles/%s/l3/%v/l3_%s_%v_%h.jpg",
-          },
-          {
-            tiledImageWidth: 1280,
-            tiledImageHeight: 1280,
-            url: URL + "/panos/center1.tiles/%s/l2/%v/l2_%s_%v_%h.jpg",
-          },
-          {
-            tiledImageWidth: 640,
-            tiledImageHeight: 640,
-            url: URL + "/panos/center1.tiles/%s/l1/%v/l1_%s_%v_%h.jpg",
-          },
-        ],
-        children: (
-          <>
-            <View
-              hlookat={0}
-              vlookat={0}
-              fovType="MFOV"
-              fov={100}
-              maxPixelZoom={2}
-              fovMin={70}
-              fovMax={140}
-              limitView="auto"
-            />
-
-            <HotSpot
-              name="hotspot1"
-              type="text"
-              atv={4}
-              scale={0.5}
-              edge="top"
-              bg={false}
-              distorted={true}
-              onClick={() => alert("点击了 hotspot1")}
-              onOver={() => setHotspotHover(true)}
-              onOut={() => setHotspotHover(false)}
-            >
-              <div className={`hotspot ${hotspotHover && "active"}`}>
-                <span>建筑名</span>
-                <div className="pointer" />
-              </div>
-            </HotSpot>
-          </>
-        ),
-      },
-    ],
-    [hotspotHover]
-  );
-
-  return (
-    <div className="demo">
-      <Krpano
-        className="krpano"
-        currentScene={currentScene}
-        passQueryParameters={true}
-      >
-        {CENTER_SCENE_LIST.map((sc) => (
-          <Scene key={sc.name} {...sc} />
-        ))}
-      </Krpano>
-    </div>
-  );
-};
-```
-
-## API
-
-<API hideTitle exports='["HotSpot"]' src='@dage/krpano/index.d.ts'></API>
+## 示例
+
+支持 `html`,但是在 vr 视角下仅支持文本和文本样式。
+
+> 支持拖拽热点,但由于需要绑定上下文关系只能直接绑定`onDown="draggable_hotspot()"`。拖拽时会调用全局`draggbleHotspotEvent`方法,能够获取到世界坐标。
+
+```tsx
+import React, { useState, useMemo, useContext, useEffect } from "react";
+import { HotSpot, Krpano, Scene, View } from "@dage/krpano";
+import "./index.css";
+
+const URL = "https://houseoss.4dkankan.com/project/leifeng-transfer";
+
+export default () => {
+  const [currentScene, setCurrentScene] = useState("center1");
+  const [hotspotHover, setHotspotHover] = useState(false);
+
+  useEffect(() => {
+    window.draggbleHotspotEvent = (ath: number, atv: number) => {
+      console.log(`ath: ${ath}, atv: ${atv}`);
+    };
+  }, []);
+
+  const CENTER_SCENE_LIST = useMemo<SceneProps[]>(
+    () => [
+      {
+        name: "center1",
+        previewUrl: URL + "/panos/center1.tiles/preview.jpg",
+        imageTagAttributes: {
+          type: "cube",
+          tileSize: 512,
+          multires: true,
+        },
+        images: [
+          {
+            tiledImageWidth: 2624,
+            tiledImageHeight: 2624,
+            url: URL + "/panos/center1.tiles/%s/l3/%v/l3_%s_%v_%h.jpg",
+          },
+          {
+            tiledImageWidth: 1280,
+            tiledImageHeight: 1280,
+            url: URL + "/panos/center1.tiles/%s/l2/%v/l2_%s_%v_%h.jpg",
+          },
+          {
+            tiledImageWidth: 640,
+            tiledImageHeight: 640,
+            url: URL + "/panos/center1.tiles/%s/l1/%v/l1_%s_%v_%h.jpg",
+          },
+        ],
+        children: (
+          <>
+            <View
+              hlookat={0}
+              vlookat={0}
+              fovType="MFOV"
+              fov={100}
+              maxPixelZoom={2}
+              fovMin={70}
+              fovMax={140}
+              limitView="auto"
+            />
+
+            <HotSpot
+              name="hotspot1"
+              type="text"
+              atv={4}
+              scale={0.5}
+              edge="top"
+              bg={false}
+              distorted={true}
+              onClick={() => alert("点击了 hotspot1")}
+              onOver={() => setHotspotHover(true)}
+              onOut={() => setHotspotHover(false)}
+            >
+              <div className={`hotspot ${hotspotHover && "active"}`}>
+                <span>建筑名</span>
+                <div className="pointer" />
+              </div>
+            </HotSpot>
+
+            <HotSpot
+              name="hotspot2"
+              type="text"
+              atv={-2.47}
+              ath={25}
+              scale={0.5}
+              edge="top"
+              bg={false}
+              distorted={true}
+              draggble={true}
+              onDown="draggable_hotspot()"
+            >
+              <div className="hotspot">
+                <span>拖拽我</span>
+                <div className="pointer" />
+              </div>
+            </HotSpot>
+          </>
+        ),
+      },
+    ],
+    [hotspotHover]
+  );
+
+  return (
+    <div className="demo">
+      <Krpano
+        className="krpano"
+        currentScene={currentScene}
+        passQueryParameters={true}
+      >
+        {CENTER_SCENE_LIST.map((sc) => (
+          <Scene key={sc.name} {...sc} />
+        ))}
+      </Krpano>
+    </div>
+  );
+};
+```
+
+## API
+
+<API hideTitle exports='["HotSpot"]' src='@dage/krpano/index.d.ts'></API>

+ 200 - 193
packages/krpano/src/components/Krpano.tsx

@@ -1,193 +1,200 @@
-import React, { useCallback, useEffect, useState } from "react";
-import { KrpanoActionProxy } from "../models";
-import { useMounted, useEventCallback } from "../hooks";
-import { IKrpanoConfig, NativeKrpanoRendererObject } from "../types";
-import { CurrentSceneContext, KrpanoRendererContext } from "../contexts";
-import { buildKrpanoAction } from "../utils";
-import { WebVR } from "./WebVR";
-import { Action } from "./Action";
-import { Layer } from "./Layer";
-import { Events } from "./Events";
-
-export interface KrpanoProps extends Omit<IKrpanoConfig, "onready" | "target"> {
-  className?: string;
-  style?: React.CSSProperties;
-  children?: React.ReactNode;
-  currentScene?: string;
-  target?: string;
-  /**
-   * webvr.xml 地址,需遵循同源策略
-   */
-  webvrUrl?: string;
-  webvrConfig?: Record<string, unknown>;
-  /**
-   * 小行星视角
-   */
-  littlePlanetIntro?: boolean;
-  onReady?: (renderer: KrpanoActionProxy) => void;
-}
-
-export const Krpano: React.FC<KrpanoProps> = ({
-  className,
-  style,
-  children,
-  currentScene,
-  target = "krpano",
-  webvrUrl,
-  webvrConfig,
-  littlePlanetIntro,
-  onReady,
-  ...rest
-}) => {
-  const [renderer, setRenderer] = useState<KrpanoActionProxy | null>(null);
-  const onReadyRef = useEventCallback(onReady);
-  const onReadyCallback = useCallback(
-    async (obj: NativeKrpanoRendererObject) => {
-      const krpano = new KrpanoActionProxy(obj);
-
-      (window as any)[krpano.name] = krpano;
-      krpano.littlePlanetIntro = littlePlanetIntro ?? false;
-      setRenderer(krpano);
-
-      if (onReadyRef.current) {
-        onReadyRef.current(krpano);
-      }
-    },
-    [onReadyRef]
-  );
-
-  useEffect(() => {
-    if (!renderer || !currentScene) return;
-
-    renderer.tagAction.waitIncludeLoaded(true).then(() => {
-      renderer.loadScene(currentScene);
-
-      renderer.littlePlanetIntro &&
-        renderer.call("skin_setup_littleplanetintro()");
-
-      renderer.littlePlanetIntro = false;
-    });
-  }, [renderer, currentScene]);
-
-  useEffect(() => {
-    if (!renderer) return;
-
-    reloadXML(renderer);
-  }, [renderer]);
-
-  const reloadXML = async (krpano: KrpanoActionProxy) => {
-    if (krpano.tagAction.syncTagStack.length) {
-      // krpano 1.21 版本以下不支持动态插入 include,只能在文本中插入后重新加载
-      const updateXmlString = new XMLSerializer().serializeToString(
-        await krpano.tagAction.createSyncTags()
-      );
-
-      krpano.call(buildKrpanoAction("loadxml", updateXmlString));
-    }
-
-    krpano.tagAction.syncTagsLoaded = true;
-    krpano.tagAction.queue.flushResolve(true);
-  };
-
-  const initKrpano = () => {
-    const defaultConfig: Partial<IKrpanoConfig> = {
-      html5: "auto",
-      xml: null,
-      mobilescale: 1,
-    };
-
-    if (typeof window.embedpano === "function") {
-      window.embedpano({
-        ...defaultConfig,
-        target,
-        onready: onReadyCallback,
-        ...rest,
-      });
-    } else {
-      throw new Error("Krpano required");
-    }
-  };
-
-  const handleNewPano = () => {
-    renderer?.set("layer[skin_loadingtext].visible", true);
-  };
-
-  const handleRemovePano = () => {
-    renderer?.set("layer[skin_loadingtext].visible", true);
-  };
-
-  const handleLoadComplete = () => {
-    setTimeout(() => {
-      renderer?.set("layer[skin_loadingtext].visible", false);
-    }, 200);
-  };
-
-  useMounted(() => {
-    initKrpano();
-  });
-
-  return (
-    <KrpanoRendererContext.Provider value={renderer}>
-      <CurrentSceneContext.Provider value={currentScene || null}>
-        {webvrUrl && <WebVR url={webvrUrl} {...webvrConfig} />}
-
-        <div id={target} className={className} style={style}>
-          {renderer ? children : null}
-        </div>
-
-        <Events
-          onNewPano={handleNewPano}
-          onRemovePano={handleRemovePano}
-          onLoadComplete={handleLoadComplete}
-        />
-
-        <Layer
-          name="skin_loadingtext"
-          type="text"
-          align="center"
-          x={5}
-          y={-5}
-          keep={true}
-          html="加载中..."
-          visible={false}
-          background={false}
-          border={false}
-          enabled={false}
-          css="color:#FFFFFF; font-family:Arial; text-align:center; font-style:italic; font-size:22px;"
-        />
-
-        <Action
-          name="skin_setup_littleplanetintro"
-          content={`
-            copy(lp_scene, xml.scene);
-            copy(lp_hlookat, view.hlookat);
-            copy(lp_vlookat, view.vlookat);
-            copy(lp_fov, view.fov);
-            copy(lp_fovmax, view.fovmax);
-            copy(lp_limitview, view.limitview);
-            set(view.fovmax, 170);
-            set(view.limitview, lookto);
-            set(view.vlookatmin, 90);
-            set(view.vlookatmax, 90);
-            lookat(calc(lp_hlookat - 180), 90, 150, 1, 0, 0);
-            set(events[lp_events].onloadcomplete,
-              delayedcall(0.5,
-                if(lp_scene === xml.scene,
-                  set(control.usercontrol, off);
-                  copy(view.limitview, lp_limitview);
-                  set(view.vlookatmin, null);
-                  set(view.vlookatmax, null);
-                  tween(view.hlookat|view.vlookat|view.fov|view.distortion, calc('' + lp_hlookat + '|' + lp_vlookat + '|' + lp_fov + '|' + 0.0),
-                    3.0, easeOutQuad,
-                    set(control.usercontrol, all);
-                    tween(view.fovmax, get(lp_fovmax));
-                    );
-                  );
-                );
-              );
-          `}
-        />
-      </CurrentSceneContext.Provider>
-    </KrpanoRendererContext.Provider>
-  );
-};
+import React, { useCallback, useEffect, useState } from "react";
+import { KrpanoActionProxy } from "../models";
+import { useMounted, useEventCallback } from "../hooks";
+import { IKrpanoConfig, NativeKrpanoRendererObject } from "../types";
+import { CurrentSceneContext, KrpanoRendererContext } from "../contexts";
+import { buildKrpanoAction } from "../utils";
+import { WebVR } from "./WebVR";
+import { Action } from "./Action";
+import { Layer } from "./Layer";
+import { Events } from "./Events";
+
+export interface KrpanoProps extends Omit<IKrpanoConfig, "onready" | "target"> {
+  className?: string;
+  style?: React.CSSProperties;
+  children?: React.ReactNode;
+  currentScene?: string;
+  target?: string;
+  /**
+   * webvr.xml 地址,需遵循同源策略
+   */
+  webvrUrl?: string;
+  webvrConfig?: Record<string, unknown>;
+  /**
+   * 小行星视角
+   */
+  littlePlanetIntro?: boolean;
+  onReady?: (renderer: KrpanoActionProxy) => void;
+}
+
+export const Krpano: React.FC<KrpanoProps> = ({
+  className,
+  style,
+  children,
+  currentScene,
+  target = "krpano",
+  webvrUrl,
+  webvrConfig,
+  littlePlanetIntro,
+  onReady,
+  ...rest
+}) => {
+  const [renderer, setRenderer] = useState<KrpanoActionProxy | null>(null);
+  const onReadyRef = useEventCallback(onReady);
+  const onReadyCallback = useCallback(
+    async (obj: NativeKrpanoRendererObject) => {
+      const krpano = new KrpanoActionProxy(obj);
+
+      (window as any)[krpano.name] = krpano;
+      krpano.littlePlanetIntro = littlePlanetIntro ?? false;
+      setRenderer(krpano);
+
+      if (onReadyRef.current) {
+        onReadyRef.current(krpano);
+      }
+    },
+    [onReadyRef]
+  );
+
+  useEffect(() => {
+    if (!renderer || !currentScene) return;
+
+    renderer.tagAction.waitIncludeLoaded(true).then(() => {
+      renderer.loadScene(currentScene);
+
+      renderer.littlePlanetIntro &&
+        renderer.call("skin_setup_littleplanetintro()");
+
+      renderer.littlePlanetIntro = false;
+    });
+  }, [renderer, currentScene]);
+
+  useEffect(() => {
+    if (!renderer) return;
+
+    reloadXML(renderer);
+  }, [renderer]);
+
+  const reloadXML = async (krpano: KrpanoActionProxy) => {
+    if (krpano.tagAction.syncTagStack.length) {
+      // krpano 1.21 版本以下不支持动态插入 include,只能在文本中插入后重新加载
+      const updateXmlString = new XMLSerializer().serializeToString(
+        await krpano.tagAction.createSyncTags()
+      );
+
+      krpano.call(buildKrpanoAction("loadxml", updateXmlString));
+    }
+
+    krpano.tagAction.syncTagsLoaded = true;
+    krpano.tagAction.queue.flushResolve(true);
+  };
+
+  const initKrpano = () => {
+    const defaultConfig: Partial<IKrpanoConfig> = {
+      html5: "auto",
+      xml: null,
+      mobilescale: 1,
+    };
+
+    if (typeof window.embedpano === "function") {
+      window.embedpano({
+        ...defaultConfig,
+        target,
+        onready: onReadyCallback,
+        ...rest,
+      });
+    } else {
+      throw new Error("Krpano required");
+    }
+  };
+
+  const handleNewPano = () => {
+    renderer?.set("layer[skin_loadingtext].visible", true);
+  };
+
+  const handleRemovePano = () => {
+    renderer?.set("layer[skin_loadingtext].visible", true);
+  };
+
+  const handleLoadComplete = () => {
+    setTimeout(() => {
+      renderer?.set("layer[skin_loadingtext].visible", false);
+    }, 200);
+  };
+
+  useMounted(() => {
+    initKrpano();
+  });
+
+  return (
+    <KrpanoRendererContext.Provider value={renderer}>
+      <CurrentSceneContext.Provider value={currentScene || null}>
+        {webvrUrl && <WebVR url={webvrUrl} {...webvrConfig} />}
+
+        <div id={target} className={className} style={style}>
+          {renderer ? children : null}
+        </div>
+
+        <Events
+          onNewPano={handleNewPano}
+          onRemovePano={handleRemovePano}
+          onLoadComplete={handleLoadComplete}
+        />
+
+        <Layer
+          name="skin_loadingtext"
+          type="text"
+          align="center"
+          x={5}
+          y={-5}
+          keep={true}
+          html="加载中..."
+          visible={false}
+          background={false}
+          border={false}
+          enabled={false}
+          css="color:#FFFFFF; font-family:Arial; text-align:center; font-style:italic; font-size:22px;"
+        />
+
+        <Action
+          name="skin_setup_littleplanetintro"
+          content={`
+            copy(lp_scene, xml.scene);
+            copy(lp_hlookat, view.hlookat);
+            copy(lp_vlookat, view.vlookat);
+            copy(lp_fov, view.fov);
+            copy(lp_fovmax, view.fovmax);
+            copy(lp_limitview, view.limitview);
+            set(view.fovmax, 170);
+            set(view.limitview, lookto);
+            set(view.vlookatmin, 90);
+            set(view.vlookatmax, 90);
+            lookat(calc(lp_hlookat - 180), 90, 150, 1, 0, 0);
+            set(events[lp_events].onloadcomplete,
+              delayedcall(0.5,
+                if(lp_scene === xml.scene,
+                  set(control.usercontrol, off);
+                  copy(view.limitview, lp_limitview);
+                  set(view.vlookatmin, null);
+                  set(view.vlookatmax, null);
+                  tween(view.hlookat|view.vlookat|view.fov|view.distortion, calc('' + lp_hlookat + '|' + lp_vlookat + '|' + lp_fov + '|' + 0.0),
+                    3.0, easeOutQuad,
+                    set(control.usercontrol, all);
+                    tween(view.fovmax, get(lp_fovmax));
+                    );
+                  );
+                );
+              );
+          `}
+        />
+
+        <Action
+          name="draggable_hotspot"
+          content={`
+            asyncloop(pressed, screentosphere(mouse.stagex, mouse.stagey, ath, atv); js(draggbleHotspotEvent(get(ath), get(atv))));
+          `}
+        />
+      </CurrentSceneContext.Provider>
+    </KrpanoRendererContext.Provider>
+  );
+};

+ 84 - 80
packages/krpano/src/types.ts

@@ -1,80 +1,84 @@
-import { KrpanoActionProxy } from "./models";
-
-declare global {
-  interface Window {
-    krpanoJS?: {
-      version: string;
-    };
-    embedpano?: (config: IKrpanoConfig) => void;
-    ReactKrpanoActionProxy?: KrpanoActionProxy;
-  }
-}
-
-export interface NativeKrpanoRendererObject {
-  buildversion: string;
-  get(key: string): any;
-  call(action: string): void;
-}
-
-/**
- * @see https://krpano.com/docu/html/#wmode
- */
-export interface IKrpanoConfig {
-  /**
-   * 全景图xml路径。需要手动设置为null才不会加载。
-   * @see https://krpano.com/docu/html/#xml
-   */
-  xml?: string | null;
-  /**  挂载点id */
-  target: string;
-  swf?: string;
-  id?: string;
-  bgcolor?: string;
-  /**
-   * @see https://krpano.com/docu/html/#html5
-   */
-  html5?: string;
-  flash?: string;
-  wmode?: string;
-  localfallback?: string;
-  vars?: Record<string, unknown>;
-  initvars?: Record<string, unknown>;
-  consolelog?: boolean;
-  basepath?: string;
-  mwheel?: boolean;
-  capturetouch?: boolean;
-  focus?: boolean;
-  webglsettings?: Record<string, unknown>;
-  webxr?: string;
-  mobilescale?: number;
-  touchdevicemousesupport?: boolean;
-  fakedevice?: string;
-  passQueryParameters?: boolean;
-  onready?: (renderer: NativeKrpanoRendererObject) => void;
-}
-
-export type EventCallback = (renderer: KrpanoActionProxy) => void;
-
-export interface XMLMeta {
-  tag: string;
-  attrs: Record<string, string | number | boolean>;
-  children?: XMLMeta[];
-}
-
-/**
- * 旋转方位
- */
-export enum ROTATE_DIRECTION {
-  UP = "up",
-  DOWN = "down",
-  LEFT = "left",
-  RIGHT = "right",
-}
-
-/**
- * 缩放动作
- */
-export enum ZOOM_ACTION {
-  IN = "in",
-  OUT = "out",
-}
+import { KrpanoActionProxy } from "./models";
+
+declare global {
+  interface Window {
+    krpanoJS?: {
+      version: string;
+    };
+    embedpano?: (config: IKrpanoConfig) => void;
+    /**
+     * 开启 dev 模式,在拖动热点时会调用此事件
+     */
+    draggbleHotspotEvent?: (ath: number, atv: number) => void;
+    ReactKrpanoActionProxy?: KrpanoActionProxy;
+  }
+}
+
+export interface NativeKrpanoRendererObject {
+  buildversion: string;
+  get(key: string): any;
+  call(action: string): void;
+}
+
+/**
+ * @see https://krpano.com/docu/html/#wmode
+ */
+export interface IKrpanoConfig {
+  /**
+   * 全景图xml路径。需要手动设置为null才不会加载。
+   * @see https://krpano.com/docu/html/#xml
+   */
+  xml?: string | null;
+  /**  挂载点id */
+  target: string;
+  swf?: string;
+  id?: string;
+  bgcolor?: string;
+  /**
+   * @see https://krpano.com/docu/html/#html5
+   */
+  html5?: string;
+  flash?: string;
+  wmode?: string;
+  localfallback?: string;
+  vars?: Record<string, unknown>;
+  initvars?: Record<string, unknown>;
+  consolelog?: boolean;
+  basepath?: string;
+  mwheel?: boolean;
+  capturetouch?: boolean;
+  focus?: boolean;
+  webglsettings?: Record<string, unknown>;
+  webxr?: string;
+  mobilescale?: number;
+  touchdevicemousesupport?: boolean;
+  fakedevice?: string;
+  passQueryParameters?: boolean;
+  onready?: (renderer: NativeKrpanoRendererObject) => void;
+}
+
+export type EventCallback = (renderer: KrpanoActionProxy) => void;
+
+export interface XMLMeta {
+  tag: string;
+  attrs: Record<string, string | number | boolean>;
+  children?: XMLMeta[];
+}
+
+/**
+ * 旋转方位
+ */
+export enum ROTATE_DIRECTION {
+  UP = "up",
+  DOWN = "down",
+  LEFT = "left",
+  RIGHT = "right",
+}
+
+/**
+ * 缩放动作
+ */
+export enum ZOOM_ACTION {
+  IN = "in",
+  OUT = "out",
+}