Przeglądaj źródła

feat: 优化版本

jinx 1 rok temu
rodzic
commit
8ad67936ce

+ 2 - 0
.env.development

@@ -1,3 +1,5 @@
 
 VITE_PUBLIC_DIR="/"
 VITE_COVER_DIR="/cover/"
+VITE_KRPANO_DIR="/krpano/"
+

+ 2 - 1
.env.production

@@ -1,2 +1,3 @@
 VITE_PUBLIC_DIR="./"
-VITE_COVER_DIR="./cover/"
+VITE_COVER_DIR="./cover/"
+VITE_KRPANO_DIR="./krpano/"

+ 1 - 0
index.html

@@ -12,6 +12,7 @@
   </head>
   <body>
     <div id="app"></div>
+    <script src="/krpano/plugins/tour.js"></script>
     <script type="module" src="/src/main.js"></script>
   </body>
 </html>

+ 96 - 0
public/krpano/index.html

@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Document</title>
+    <style>
+      * {
+        padding: 0;
+        margin: 0;
+      }
+      #mousepos {
+        position: fixed;
+        top: 100px;
+        left: 100px;
+        color: #fff;
+        width: 100px;
+        height: 100px;
+        z-index: 1;
+        background: rgba(0, 0, 0, 0.5);
+      }
+    </style>
+  </head>
+  <body>
+    <div id="pano" style="width: 100vw; height: 100vh" onclick="track_mouse()"></div>
+    <div id="mousepos" onclick="track_mouse()"></div>
+  </body>
+  <script src="./plugins/tour.js"></script>
+  <script>
+    let krpano = null;
+    embedpano({ xml: "./tour.xml", target: "pano", id: "krpanoSWFObject", passQueryParameters: true, onready: krpano_onready_callback });
+    window.hover = function () {
+      console.error("hover");
+    };
+    window.over = function () {
+      console.error("over");
+    };
+    function krpano_onready_callback(krpano_interface) {
+      krpano = krpano_interface;
+      window.krpano = krpano;
+
+      // console.error(krpano);
+      setTimeout(() => {
+        krpano.set("autorotate.enabled", false);
+      }, 1000);
+
+      // 监听鼠标移动事件;
+      // krpano.addAction(function (action) {
+      //   if (action.event == "MOUSE_MOVE") {
+      //     // 获取鼠标的水平和垂直角度
+      //     var ath = krpano.get("mouse.x") - krpano.get("layer.width") / 2;
+      //     var atv = krpano.get("mouse.y") - krpano.get("layer.height") / 2;
+
+      //     // 输出或处理ath和atv值
+      //     console.log("ath:", ath, "atv:", atv);
+      //   }
+      // });
+      console.error(krpano);
+    }
+    // 场景跳转 index:0,1,2
+    var track_mouse_enabled = false;
+    var track_mouse_interval_id = null;
+
+    function track_mouse_interval_callback() {
+      var mx = krpano.get("mouse.x");
+      var my = krpano.get("mouse.y");
+      var pnt = krpano.screentosphere(mx, my);
+      var h = pnt.x;
+      var v = pnt.y;
+      // document.getElementById("mousepos").innerHTML = 'x="' + mx + '" y="' + my + '" ath="' + h.toFixed(2) + '" atv="' + v.toFixed(2) + '"';
+      console.error('x="' + mx + '" y="' + my + '" ath="' + h.toFixed(2) + '" atv="' + v.toFixed(2) + '"');
+    }
+
+    function track_mouse() {
+      // var krpano = document.getElementById("krpanoSWFObject");
+      console.error(krpano.get("hotspot[eee]"));
+      krpano.set("autorotate.enabled", false);
+      krpano.call("hotspotClicked");
+      track_mouse_interval_callback();
+      // if (krpano) {
+      //   if (track_mouse_enabled == false) {
+      //     // enable - call 60 times per second
+      //     track_mouse_interval_id = setInterval(track_mouse_interval_callback, 1000.0 / 60.0);
+
+      //     track_mouse_enabled = true;
+      //   } else {
+      //     // disable
+      //     clearInterval(track_mouse_interval_id);
+      //     document.getElementById("mousepos").innerHTML = "";
+
+      //     track_mouse_enabled = false;
+      //   }
+      // }
+    }
+  </script>
+</html>

Plik diff jest za duży
+ 19 - 0
public/krpano/plugins/scrollarea.js


Plik diff jest za duży
+ 12 - 0
public/krpano/plugins/tour.js


Plik diff jest za duży
+ 5 - 0
public/krpano/plugins/webvr.js


+ 881 - 0
public/krpano/plugins/webvr.xml

@@ -0,0 +1,881 @@
+<krpano>
+
+	<!-- load the WebVR plugin and assign it to a 'webvr' variable for easier usage -->
+	<plugin name="WebVR" devices="html5" keep="true"
+	        url="webvr.js"
+	        onloaded="copy(webvr, plugin[WebVR]);"
+	        mousespeed="0.00125"
+	        multireslock="true"
+	        mobilevr_support="true"
+	        mobilevr_ipd="63.5"
+	        mobilevr_screensize="auto"
+	        mobilevr_lens_overlap="1.0"
+	        mobilevr_lens_fov="96"
+	        mobilevr_lens_dist="0.6"
+	        mobilevr_lens_dist2="1|0|0|0"
+	        mobilevr_lens_ca="0.0"
+	        mobilevr_lens_vign="100"
+	        mobilevr_webvr_dist="false"
+	        mobilevr_wakelock="true"
+	        mobilevr_sensor_mode="3"
+	        mobilevr_autocalibration="false"
+	        mobilevr_touch_support="false"
+	        mobilevr_fake_support="false"
+	        vr_cursor="hotspot[vr_cursor]"
+	        vr_cursor_enabled="true"
+	        vr_cursor_onover="if(handcursor, tween(hotspot[vr_cursor].scale,0.4,0.1); vr_auto_click(get(vr_timeout)); );"
+	        vr_cursor_onout="tween(hotspot[vr_cursor].scale,0.3,0.1);"
+	        onavailable="webvr_onavailable();"
+	        onunavailable=""
+	        onunknowndevice="set(ask_user_for_screensize,true);"
+	        onentervr="webvr_onentervr();"
+	        onexitvr="webvr_onexitvr();"
+	        />
+
+	
+	<!-- a custom xml data structure with the supported VR headsets -->
+	<vrheadsets>
+		<headset name="cb1" caption="Cardboard A"   overlap="1.10" fov="96.0"  dist="1.00" dist2="1|0|0|0" ca="0.000" vig="100" />
+		<headset name="cb2" caption="Cardboard B"   overlap="1.00" fov="96.0"  dist="0.60" dist2="1|0|0|0" ca="0.000" vig="100" />
+		<headset name="gvr" caption="GearVR"        overlap="1.00" fov="112.0" dist="0.95" dist2="1|0|0|0" ca="0.090" vig="100" />
+		<headset name="hom" caption="HOMiDO"        overlap="1.00" fov="101.0" dist="1.10" dist2="1|0|0|0" ca="0.075" vig="100" />
+		<headset name="one" caption="VR ONE"        overlap="1.00" fov="109.9" dist="0.00" dist2="1.139|0.093|0.018|0.207" ca="0.090" vig="35" />
+		<headset name="ccr" caption="ColorCross VR" overlap="1.00" fov="70.0"  dist="0.65" dist2="1|0|0|0" ca="0.000" vig="100" />
+		<headset name="nod" caption="No Distortion" overlap="1.00" fov="96.0"  dist="0.00" dist2="1|0|0|0" ca="0.000" vig="100" />
+	</vrheadsets>
+
+
+	<!-- the VR cursor hotspot -->
+	<hotspot name="vr_cursor" keep="true"
+	         url="webvr_cursor_80x80_17f.png"
+	         visible="false"
+	         enabled="false"
+	         distorted="true"
+	         crop="0|0|80|80"
+	         scale="0.3"
+	         depth="1000"
+	         />
+
+
+	<!-- vr_auto_click() - call this action in the onover event of a
+	     hotspot to trigger automatically a click after some time.  -->
+	<action name="vr_auto_click">
+		if(webvr.isenabled,
+			if(%1 != null, set(vr_aclk_timeout, %1), set(vr_aclk_timeout, 2000));
+			copy(vr_aclk_t1, timertick);
+			set(vr_aclk_waiting, true);
+			set(hotspot[vr_cursor].crop,'0|0|80|80');
+
+			asyncloop(vr_aclk_waiting,
+				sub(dt, timertick,vr_aclk_t1);
+
+				if(!hovering,
+					set(vr_aclk_waiting, false);
+					set(hotspot[vr_cursor].crop,'0|0|80|80');
+				  ,
+					div(f, dt, vr_aclk_timeout);
+					mul(f, 16);
+					roundval(f);
+					Math.min(f, 16);
+					mul(f, 80);
+
+					txtadd(hotspot[vr_cursor].crop,get(f),'|0|80|80');
+
+					<!-- wait another 100ms delay after finishing the animation before doing the click -->
+					sub(dt, 100);
+					if(dt GT vr_aclk_timeout,
+						set(vr_aclk_waiting,false);
+						set(hotspot[vr_cursor].crop,'0|0|80|80');
+						<!-- call onclick -->
+						onclick();
+					  );
+				  );
+				);
+		  );
+	</action>
+
+
+	<!-- by pressing SPACE the Oculus Rift could be re-centered -->
+	<events name="webvr_events" devices="html5" keep="true"
+	        onkeydown="if(keycode==32, webvr.resetSensor(0) );"
+	        onmousedown="if(webvr AND webvr.isenabled, webvr_showbuttons() );"
+	        />
+
+
+	<!-- when WebVR support is available show an EnterVR button -->
+	<action name="webvr_onavailable">
+
+		delayedcall(0.5, tween(layer[webvr_enterbutton].alpha,1.0); );
+	</action>
+
+
+	<action name="webvr_onentervr">
+		trace('vr-in');
+		tween(layer[webvr_enterbutton].alpha,0,0);
+
+		webvr_showbuttons();
+		webvr_hide_all_non_vr_layers();
+
+		<!-- when the screen size is unknown an no custom size is set, open the setup screen on entering the VR mode -->
+		if(webvr.ismobilevr == true AND !webvr.isfake AND ask_user_for_screensize == true AND webvr.mobilevr_screensize == 'auto',
+			set(ask_user_for_screensize, false);
+			<!-- vr_setup(); -->
+		  );
+		if(webvr.isfake,
+			webvr_show_fakemode_info(true);
+		  );
+	</action>
+
+
+	<action name="webvr_onexitvr">
+		trace('vr-out');
+		stopdelayedcall(vr_button_fadeout);
+
+		tween(layer[webvr_enterbutton].alpha,1);
+		tween(layer[webvr_exitbutton].alpha,0);
+		<!-- tween(layer[webvr_setupbutton].alpha,0); -->
+		
+		webvr_show_fakemode_info(false);
+		webvr_restore_layers();
+		js(window.onExitVrStatus);
+	</action>
+
+
+	<action name="webvr_hide_all_non_vr_layers">
+		for(set(i,0), i LT layer.count, inc(i),
+			copy(lr, layer[get(i)]);
+			if(lr.vr !== true,
+				copy(lr.vr_backup_visible, lr.visible);
+				set(lr.visible, false);
+			  );
+		  );
+		for(set(i,0), i LT hotspot.count, inc(i),
+			copy(lh, hotspot[get(i)]);
+			if(lh.vr !== true,
+				copy(lh.vr_backup_visible, lh.visible);
+				set(lh.visible, false);
+			  );
+		  );
+	</action>
+
+	<action name="webvr_restore_layers">
+		for(set(i,0), i LT layer.count, inc(i),
+			copy(lr, layer[get(i)]);
+			if(lr.vr_backup_visible,
+				copy(lr.visible, lr.vr_backup_visible);
+				delete(lr.vr_backup_visible);
+			  );
+		  );
+		for(set(i,0), i LT hotspot.count, inc(i),
+			copy(lh, hotspot[get(i)]);
+			if(lh.vr_backup_visible,
+				copy(lh.visible, lh.vr_backup_visible);
+				delete(lh.vr_backup_visible);
+			  );
+		  );
+	</action>
+	
+	<action name="webvr_show_fakemode_info">
+		if('%1' == 'true',
+			addlayer(webvr_fakemode_info);
+			set(layer[webvr_fakemode_info].url, '%SWFPATH%/krpano/plugins/textfield.swf');
+			set(layer[webvr_fakemode_info].keep, true);
+			set(layer[webvr_fakemode_info].align, 'bottom');
+			set(layer[webvr_fakemode_info].y, 80);
+			set(layer[webvr_fakemode_info].background, false);
+			set(layer[webvr_fakemode_info].css, 'color:#FFFFFF;text-align:center;');
+			set(layer[webvr_fakemode_info].html, '');
+		  ,
+			removelayer(webvr_fakemode_info);
+		  );
+	</action>
+	
+	
+	<!-- ensure the same scaling on mobiles (regardless if mobilescale is 0.5 or 1.0) -->
+	<krpano webvr_setup_scale="calc:(1.0 + 1.0*(device.mobile AND stagescale LT 1.0)) / (1.0 + 1.0*device.mobile)"
+	        webvr_button_scale.normal="1.0"
+	        webvr_button_scale.mobile="1.6"
+	        />
+
+	
+	<!-- the EnterVR/ExitVR and SetupVR buttons -->
+	<style name="webvr_button_style"
+	       url="%SWFPATH%/krpano/plugins/textfield.swf"
+	       backgroundcolor="0x000000"
+	       backgroundalpha="0.5"
+	       roundedge="calc:9*webvr_setup_scale*webvr_button_scale"
+	       css="calc:'color:#FFFFFF;font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       padding="calc:6*webvr_setup_scale*webvr_button_scale + ' ' + 10*webvr_setup_scale*webvr_button_scale"
+	       />
+	
+	<layer name="webvr_enterbutton" keep="true" vr="true"
+	       style="webvr_button_style"
+	       html=""
+	       align="top" y="24"
+	       autoalpha="true" alpha="0.0"
+	       onclick="webvr.enterVR();"
+	       />
+
+	<layer name="webvr_exitbutton" keep="true" vr="true"
+	       style="webvr_button_style"
+	       html="退出VR模式"
+	       align="top" y="24"
+	       autoalpha="true" alpha="0.0"
+	       onclick="webvr.exitVR();"
+	       />
+
+	<layer name="webvr_setupbutton" keep="true" vr="true"
+	       autoalpha="true" alpha="0.0"
+	       />
+
+	<action name="webvr_showbuttons">
+		stopdelayedcall(vr_button_fadeout);
+		if(webvr.ismobilevr,
+			tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 1.0|1.0, 0.25);
+			delayedcall(vr_button_fadeout, 0.5, tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 0.0|0.0, 1.0); );
+		  ,
+			tween(layer[webvr_exitbutton].alpha, 1.0, 0.25);
+			delayedcall(vr_button_fadeout, 0.5, tween(layer[webvr_exitbutton].alpha, 0.0, 1.0); );
+		  );
+	</action>
+
+
+
+	<!--
+		VR Setup
+	-->
+
+	<action name="vr_setup">
+		<!-- disable cursor -->
+		set(webvr.vr_cursor_enabled, false);
+		
+		<!-- hide VR buttons -->
+		tween(layer[webvr_exitbutton].alpha,0);
+		tween(layer[webvr_setupbutton].alpha,0);
+		
+		<!-- create background layer -->
+		addlayer(vr_setup_bg);
+		set(layer[vr_setup_bg].type, container);
+		set(layer[vr_setup_bg].bgcolor, 0x000000);
+		set(layer[vr_setup_bg].bgalpha, 0.5);
+		set(layer[vr_setup_bg].bgcapture, true);
+		set(layer[vr_setup_bg].handcursor, false);
+		set(layer[vr_setup_bg].align, lefttop);
+		set(layer[vr_setup_bg].width, 100%);
+		set(layer[vr_setup_bg].height, 100%);
+		set(layer[vr_setup_bg].zorder, 99999);
+		
+		<!-- get and prepare device infos and settings -->
+		copy(i_screensize, webvr.mobilevr_screensize);
+		if(i_screensize == 'auto', copy(i_screensize, webvr.devicesize));
+		if(i_screensize LE 0, set(i_screensize, 5.0));
+		roundval(i_screensize, 1);
+		txtadd(i_screensize, ' inch');
+
+		copy(i_ipd, webvr.mobilevr_ipd);
+		roundval(i_ipd, 1);
+		txtadd(i_ipd, ' mm');
+
+		copy(i_fov, webvr.mobilevr_lens_fov);
+		roundval(i_fov, 1);
+
+		copy(i_dist, webvr.mobilevr_lens_dist);
+		roundval(i_dist, 2);
+		
+		copy(i_dist2, webvr.mobilevr_lens_dist2);
+		txtsplit(i_dist2, '|', i_dist2_k1, i_dist2_k2, i_dist2_k3, i_dist2_k4);
+		mul(i_dist2_k1,1);
+		mul(i_dist2_k2,10);
+		mul(i_dist2_k3,10);
+		mul(i_dist2_k4,10);
+		roundval(i_dist2_k1,2);
+		roundval(i_dist2_k2,2);
+		roundval(i_dist2_k3,2);
+		roundval(i_dist2_k4,2);
+
+		copy(i_vig, webvr.mobilevr_lens_vign);
+		roundval(i_vig, 0);
+		
+		copy(i_overlap, webvr.mobilevr_lens_overlap);
+		roundval(i_overlap, 2);
+		
+		copy(i_ca, webvr.mobilevr_lens_ca);
+		roundval(i_ca, 3);
+
+		set(i_headset, 'Custom');
+		for(set(i,0), i LT vrheadsets.headset.count, inc(i),
+			copy(hs, vrheadsets.headset[get(i)]);
+			if(i_overlap == hs.overlap AND i_fov == hs.fov AND i_dist == hs.dist AND i_dist2 == hs.dist2 AND i_ca == hs.ca AND i_vig == hs.vig , copy(i_headset, hs.caption));
+		   );
+
+		<!-- when the screen size is unknown, mark it red -->
+		set(known_size, true);
+		set(sizcol, #FFFFFF);
+		copy(i_devicename, webvr.devicename);
+		if(i_devicename == 'Unknown',
+			if(webvr.mobilevr_screensize == 'auto',
+				set(sizcol, #AA0000);
+				set(known_size, false);
+			  ,
+				set(i_devicename, 'Custom');
+			  );
+		  );
+
+		
+		<!-- create layer for the main menu -->
+		addlayer(vr_setup_m1);
+		set(layer[vr_setup_m1].type, container);
+		set(layer[vr_setup_m1].parent, vr_setup_bg);
+		set(layer[vr_setup_m1].align, lefttop);
+		set(layer[vr_setup_m1].width, 100%);
+		set(layer[vr_setup_m1].height, 100%);
+		
+		<!-- create layer for the headset customization menu -->
+		addlayer(vr_setup_m3);
+		set(layer[vr_setup_m3].type, container);
+		set(layer[vr_setup_m3].parent, vr_setup_bg);
+		set(layer[vr_setup_m3].align, lefttop);
+		set(layer[vr_setup_m3].width, 100%);
+		set(layer[vr_setup_m3].height, 100%);
+		set(layer[vr_setup_m3].visible, false);
+		
+		<!-- create layer for the calibration menu -->
+		addlayer(vr_setup_m2);
+		set(layer[vr_setup_m2].type, container);
+		set(layer[vr_setup_m2].parent, vr_setup_bg);
+		set(layer[vr_setup_m2].align, lefttop);
+		set(layer[vr_setup_m2].width, 100%);
+		set(layer[vr_setup_m2].height, 100%);
+		set(layer[vr_setup_m2].visible, false);
+		
+		<!-- create the text elements -->
+		set(vr_setup_text_parent, 'vr_setup_m1');
+		vr_setup_createtext(vr_setup_title, 'VR设置',       center, center, 0, -225, #FFFFFF,     false);
+
+		vr_setup_createtext(vr_setup_dvn1, '设备:',         center, right,  0, -145, #FFFFFF,     true, vr_setup_select('screen') );
+		vr_setup_createtext(vr_setup_dvn2, get(i_devicename), center, left,   0, -145, get(sizcol), true, vr_setup_select('screen') );
+		vr_setup_createtext(vr_setup_siz1, '屏幕尺寸:',     center, right,  0, -105, #FFFFFF,     true, vr_setup_select('screen') );
+		vr_setup_createtext(vr_setup_siz2, get(i_screensize), center, left,   0, -105, get(sizcol), true, vr_setup_select('screen') );
+
+		vr_setup_createtext(vr_setup_ipd1, '瞳距:',            center, right,  0,  -35, #FFFFFF,     true, vr_setup_select('ipd') );
+		vr_setup_createtext(vr_setup_ipd2, get(i_ipd),        center, left,   0,  -35, #FFFFFF,     true, vr_setup_select('ipd') );
+
+		vr_setup_createtext(vr_setup_hmd1, '设置头显:',     center, right,  0,  +35, #FFFFFF,     true, vr_setup_select('headset') );
+		vr_setup_createtext(vr_setup_hmd2, get(i_headset),    center, left,   0,  +35, #FFFFFF,     true, vr_setup_select('headset') );
+		
+		vr_setup_createtext(vr_setup_hmd3, '调节头显',       center, center, 0,  +75, #FFFFFF,     true, set(background,true), set(background,false), vr_setup_customize_headset() );
+
+		
+
+		if(webvr.iswebvr == false,
+			vr_setup_createtext(vr_setup_cal, '陀螺仪校准',   center, center,    0, +145, #FFFFFF,     true, set(background,true), set(background,false), vr_setup_calibration() );
+		  );
+
+		vr_setup_createtext(vr_setup_sav, '保存',          center, center, -200, +225, #FFFFFF,     true, set(background,true), set(background,false), vr_setup_save() );
+		vr_setup_createtext(vr_setup_rst, '重置',         center, center,    0, +225, #FFFFFF,     true, set(background,true), set(background,false), vr_setup_reset() );
+		vr_setup_createtext(vr_setup_cls, '关闭',         center, center, +200, +225, #FFFFFF,     true, set(background,true), set(background,false), vr_setup_close() );
+		
+		<!-- and the adjusting buttons -->
+		vr_setup_createbutton(vr_setup_btn1, '&#60;', left,  left,  5%, -35, #FFFFFF, true, null);
+		vr_setup_createbutton(vr_setup_btn2, '&#62;', right, right, 5%, -35, #FFFFFF, true, null);
+		
+		
+		<!-- create the customize_headset text elements -->
+		set(vr_setup_text_parent, 'vr_setup_m3');
+		vr_setup_createtext(vr_setup_m31, '头显设置', center, center, 0, -225, #FFFFFF, false);
+		
+		vr_setup_createtext(vr_setup_fov1,  'FOV:',           center, right,  0,  -80,  #FFFFFF,    true, vr_setup_select('fov') );
+		vr_setup_createtext(vr_setup_fov2, get(i_fov),        center, left,   0,  -80,  #FFFFFF,    true, vr_setup_select('fov') );
+		vr_setup_createtext(vr_setup_dst1, 'Distortion:',     center, right,  0,  -32,  #FFFFFF,    true, vr_setup_select('dist') );
+		vr_setup_createtext(vr_setup_dst2, get(i_dist),       center, left,   0,  -32,  #FFFFFF,    true, vr_setup_select('dist') );
+		vr_setup_createtext(vr_setup_d2tx, 'Dist2:',          center, right,  0,  +16,  #FFFFFF,    true, vr_setup_select('dist2k1') );
+		vr_setup_createtext(vr_setup_d2k1, get(i_dist2_k1),   center, left,   0,  +16,  #FFFFFF,    true, vr_setup_select('dist2k1') );
+		vr_setup_createtext(vr_setup_d2k2, get(i_dist2_k2),   center, left, +100, +16,  #FFFFFF,    true, vr_setup_select('dist2k2') );
+		vr_setup_createtext(vr_setup_d2k3, get(i_dist2_k3),   center, left, +200, +16,  #FFFFFF,    true, vr_setup_select('dist2k3') );
+		vr_setup_createtext(vr_setup_d2k4, get(i_dist2_k4),   center, left, +300, +16,  #FFFFFF,    true, vr_setup_select('dist2k4') );
+		
+		
+		vr_setup_createtext(vr_setup_cac1, 'CA Corr:',        center, right,  0,  +64,  #FFFFFF,    true, vr_setup_select('ca') );
+		vr_setup_createtext(vr_setup_cac2, get(i_ca),         center, left,   0,  +64,  #FFFFFF,    true, vr_setup_select('ca') );
+		vr_setup_createtext(vr_setup_vig1, 'Vignette:',       center, right,  0, +112,  #FFFFFF,    true, vr_setup_select('vignette') );
+		vr_setup_createtext(vr_setup_vig2, get(i_vig),        center, left,   0, +112,  #FFFFFF,    true, vr_setup_select('vignette') );
+		vr_setup_createtext(vr_setup_olp1, 'Overlap:',        center, right,  0, +160,  #FFFFFF,    true, vr_setup_select('overlap') );
+		vr_setup_createtext(vr_setup_olp2, get(i_overlap),    center, left,   0, +160,  #FFFFFF,    true, vr_setup_select('overlap') );
+				
+		vr_setup_createtext(vr_setup_m35, '关闭',       center, center, 0, +225, #FFFFFF, true, set(background,true), set(background,false), vr_setup_close_sub_menus() );
+		
+		
+		<!-- create the calibration text elements -->
+		set(vr_setup_text_parent, 'vr_setup_m2');
+		vr_setup_createtext(vr_setup_cb1, '陀螺仪', center, center, 0, -225, #FFFFFF, false);
+		vr_setup_createtext(vr_setup_cb2, '水平放置后校准', center, center, 0, -95, #FFFFFF, false, vr_setup_select('screen') );
+		vr_setup_createtext(vr_setup_cb3, '校准',   center, center, 0,  +55, #FFFFFF, true, set(background,true), set(background,false), vr_setup_do_calibration() );
+		vr_setup_createtext(vr_setup_cb4, '重置',       center, center, 0, +125, #FFFFFF, true, set(background,true), set(background,false), webvr.resetcalibration() );
+		vr_setup_createtext(vr_setup_cb5, '关闭',       center, center, 0, +225, #FFFFFF, true, set(background,true), set(background,false), vr_setup_close_sub_menus() );
+		
+		vr_setup_createtext(vr_setup_cb6, 'Calibrating...',      bottom, center, 0, 40, #FFFFFF, false, null );
+		vr_setup_createtext(vr_setup_cb7, 'Calibration okay.',   bottom, center, 0, 40, #FFFFFF, false, null );
+		vr_setup_createtext(vr_setup_cb8, 'Calibration failed!', bottom, center, 0, 40, #FFFFFF, false, null );
+		set(layer[vr_setup_cb6].autoalpha, true);
+		set(layer[vr_setup_cb7].autoalpha, true);
+		set(layer[vr_setup_cb8].autoalpha, true);
+		set(layer[vr_setup_cb6].alpha, 0.0);
+		set(layer[vr_setup_cb7].alpha, 0.0);
+		set(layer[vr_setup_cb8].alpha, 0.0);
+		
+		
+		<!-- pre-select the screen size for adjusting when it is unknown, otherwise the IPD -->
+		if(known_size == false,
+			vr_setup_select('screen', true);
+		  ,
+			vr_setup_select('ipd', true);
+		  );
+	</action>
+
+
+
+	<action name="vr_setup_createtext">
+		<!--
+			%1 = name
+			%2 = text
+			%3 = align
+			%4 = edge
+			%5 = x
+			%6 = y
+			%7 = color
+			%8 = enabled
+			%9 = ondown
+			%10 = onup
+			%11 = onclick
+		-->
+		addlayer(%1);
+		set(layer[%1].parent, get(vr_setup_text_parent));
+		set(layer[%1].url, '%SWFPATH%/krpano/plugins/textfield.swf');
+		set(layer[%1].css, calc('text-align:%3;color:%7;font-size:'+40*webvr_setup_scale+'px;font-weight:bold;'));
+		set(layer[%1].padding, calc(0 + ' ' + 8*webvr_setup_scale));
+		set(layer[%1].roundedge, calc(8*webvr_setup_scale));
+		set(layer[%1].background, false);
+		set(layer[%1].backgroundcolor, 0xFFFFFF);
+		set(layer[%1].backgroundalpha, 0.25);
+		set(layer[%1].align, %3);
+		set(layer[%1].edge, %4);
+		set(layer[%1].x, calc(%5 * webvr_setup_scale));
+		set(layer[%1].y, calc(%6 * webvr_setup_scale));
+		set(layer[%1].html, %2);
+		set(layer[%1].enabled, %8);
+		set(layer[%1].ondown, %9);
+		set(layer[%1].onup, %10);
+		set(layer[%1].onclick, %11);
+	</action>
+
+
+	<action name="vr_setup_createbutton">
+		vr_setup_createtext(%1,%2,%3,%4,%5,%6,%7,%8,%9);
+		set(layer[%1].css, calc('vertical-align:middle;text-align:center;color:%7;font-size:'+60*webvr_setup_scale+'px;font-weight:bold;'));
+		set(layer[%1].background, true);
+		set(layer[%1].padding, 0);
+		set(layer[%1].roundedge, calc(40 * webvr_setup_scale));
+		set(layer[%1].width, calc(70 * webvr_setup_scale));
+		set(layer[%1].height, calc(70 * webvr_setup_scale));
+		set(layer[%1].vcenter, true);
+	</action>
+
+
+	<action name="vr_setup_reset">
+		<!-- reset to the defaults -->
+		set(webvr.mobilevr_screensize, 'auto');
+		copy(i_screensize, webvr.devicesize);
+		if(i_screensize LE 0, set(i_screensize, 5.0));
+		roundval(i_screensize, 1);
+		set(layer[vr_setup_dvn2].html, get(webvr.devicename));
+		txtadd(layer[vr_setup_siz2].html, get(i_screensize), ' inch');
+
+		set(webvr.mobilevr_ipd, 63.5);
+		copy(i_ipd, webvr.mobilevr_ipd);
+		roundval(i_ipd, 1);
+		txtadd(layer[vr_setup_ipd2].html, get(i_ipd), ' mm');
+
+		<!-- set fake custom lens settings and call 'next' headset to switch to the default 'Cardboard' settings -->
+		set(webvr.mobilevr_lens_fov, 100);
+		set(webvr.mobilevr_lens_dist, 0.5);
+		set(webvr.mobilevr_lens_vign, 100);
+		set(webvr.mobilevr_lens_overlap, 1.0);
+		set(webvr.mobilevr_lens_ca, 0.0);
+		vr_setup_change_headset(+1);
+
+		vr_setup_select(get(selected_var));
+	</action>
+
+
+	<action name="vr_setup_close">
+		<!-- 2. parameter == true => remove children elements too -->
+		removelayer(vr_setup_bg, true);
+		
+		<!-- enable cursor -->
+		set(webvr.vr_cursor_enabled, true);
+	</action>
+
+
+	<action name="vr_setup_save">
+		webvr.saveSettings();
+		vr_setup_close();
+	</action>
+	
+	
+	<action name="vr_setup_customize_headset">
+		set(layer[vr_setup_bg].bgalpha, 0.1);
+		
+		set(layer[vr_setup_m1].visible,false);
+		set(layer[vr_setup_m2].visible,false);
+		set(layer[vr_setup_m3].visible,true);
+		
+		set(layer[vr_setup_hmd1].parent, vr_setup_m3);
+		set(layer[vr_setup_hmd2].parent, vr_setup_m3);
+		set(layer[vr_setup_btn1].parent, vr_setup_m3);
+		set(layer[vr_setup_btn2].parent, vr_setup_m3);
+		
+		set(layer[vr_setup_hmd1].y, calc(-145 * webvr_setup_scale));
+		set(layer[vr_setup_hmd2].y, calc(-145 * webvr_setup_scale));
+		
+		copy(old_selection, selected_var);
+		vr_setup_select('headset');
+	</action>
+	
+	
+
+	<action name="vr_setup_calibration">
+		set(layer[vr_setup_m1].visible,false);
+		set(layer[vr_setup_m2].visible,true);
+	</action>
+	
+	<action name="vr_setup_close_sub_menus">
+		set(layer[vr_setup_bg].bgalpha, 0.5);
+		
+		set(layer[vr_setup_m1].visible,true);
+		set(layer[vr_setup_m2].visible,false);
+		set(layer[vr_setup_m3].visible,false);
+		
+		set(layer[vr_setup_hmd1].parent, vr_setup_m1);
+		set(layer[vr_setup_hmd2].parent, vr_setup_m1);
+		set(layer[vr_setup_btn1].parent, vr_setup_m1);
+		set(layer[vr_setup_btn2].parent, vr_setup_m1);
+		
+		set(layer[vr_setup_hmd1].y, calc(+35 * webvr_setup_scale));
+		set(layer[vr_setup_hmd2].y, calc(+35 * webvr_setup_scale));
+		
+		if(old_selection,
+			vr_setup_select(get(old_selection));
+			delete(old_selection);
+		  );
+	</action>
+	
+	<action name="vr_setup_do_calibration">
+		if(!webvr.isfake,
+			tween(layer[vr_setup_cb6].alpha, 1.0, 0.1);
+			tween(layer[vr_setup_cb7].alpha, 0.0, 0.1);
+			tween(layer[vr_setup_cb8].alpha, 0.0, 0.1);
+			webvr.calibrate(
+				tween(layer[vr_setup_cb6].alpha, 0.0, 0.1);
+				tween(layer[vr_setup_cb7].alpha, 1.0, 0.1);
+				delayedcall(2.0, tween(layer[vr_setup_cb7].alpha, 0.0, 0.25) );
+			  ,
+				tween(layer[vr_setup_cb6].alpha, 0.0, 0.1);
+				tween(layer[vr_setup_cb8].alpha, 1.0, 0.1);
+				delayedcall(2.0, tween(layer[vr_setup_cb8].alpha, 0.0, 0.25) );
+			  );
+		  );
+	</action>
+
+	<action name="vr_setup_update_dist2">
+		txtadd(webvr.mobilevr_lens_dist2, get(i_dist2_k1), '|', calc(i_dist2_k2/10.0), '|', calc(i_dist2_k3/10.0), '|', calc(i_dist2_k4/10.0));
+		vr_setup_change_headset(0);
+	</action>
+
+	<action name="vr_setup_select">
+		<!-- select a setting for adjusting -->
+		set(layer[vr_setup_siz2].background, false);
+		set(layer[vr_setup_ipd2].background, false);
+		set(layer[vr_setup_hmd2].background, false);
+		set(layer[vr_setup_fov2].background, false);
+		set(layer[vr_setup_dst2].background, false);
+		set(layer[vr_setup_d2k1].background, false);
+		set(layer[vr_setup_d2k2].background, false);
+		set(layer[vr_setup_d2k3].background, false);
+		set(layer[vr_setup_d2k4].background, false);
+		set(layer[vr_setup_vig2].background, false);
+		set(layer[vr_setup_cac2].background, false);
+		set(layer[vr_setup_olp2].background, false);
+
+		set(selected_setting, null);
+		delete(selected_var_value);
+
+		set(layer[vr_setup_btn1].ondown, vr_setup_change_ondown(-1) );
+		set(layer[vr_setup_btn2].ondown, vr_setup_change_ondown(+1) );
+		set(selected_var_callback, null);
+
+		set(selected_var, %1);
+
+		if(selected_var == 'screen',
+			set(selected_setting,      vr_setup_siz2);
+			set(selected_var_name,     'webvr.mobilevr_screensize');
+			set(selected_var_postfix,  ' inch');
+			copy(selected_var_value,   get(selected_var_name));
+			if(selected_var_value == 'auto', copy(selected_var_value, webvr.devicesize));
+			if(selected_var_value LE 0, set(selected_var_value, 5.0));
+			set(selected_var_step,     0.1);
+			set(selected_var_min,      4);
+			set(selected_var_max,      10);
+			set(selected_var_round,    1);
+			set(selected_var_callback, vr_setup_change_screen() );
+		  );
+
+		if(selected_var == 'ipd',
+			set(selected_setting,      vr_setup_ipd2);
+			set(selected_var_name,     'webvr.mobilevr_ipd');
+			set(selected_var_postfix,  ' mm');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.1);
+			set(selected_var_min,      40);
+			set(selected_var_max,      80);
+			set(selected_var_round,    1);
+		  );
+
+		if(selected_var == 'headset',
+			set(selected_setting,      vr_setup_hmd2);
+			set(layer[vr_setup_btn1].ondown, vr_setup_change_headset(-1) );
+			set(layer[vr_setup_btn2].ondown, vr_setup_change_headset(+1) );
+		  );
+
+		if(selected_var == 'fov',
+			set(selected_setting,      vr_setup_fov2);
+			set(selected_var_name,     'webvr.mobilevr_lens_fov');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.1);
+			set(selected_var_min,      40);
+			set(selected_var_max,      179);
+			set(selected_var_round,    1);
+			set(selected_var_callback, vr_setup_change_headset(0) );
+		  );
+
+		if(selected_var == 'dist',
+			set(selected_setting,      vr_setup_dst2);
+			set(selected_var_name,     'webvr.mobilevr_lens_dist');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      0);
+			set(selected_var_max,      5);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_change_headset(0) );
+		  );
+		
+		if(selected_var == 'dist2k1',
+			set(selected_setting,      vr_setup_d2k1);
+			set(selected_var_name,     'i_dist2_k1');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      -9);
+			set(selected_var_max,      +9);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_update_dist2() );
+		  );
+		
+		if(selected_var == 'dist2k2',
+			set(selected_setting,      vr_setup_d2k2);
+			set(selected_var_name,     'i_dist2_k2');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      -9);
+			set(selected_var_max,      +9);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_update_dist2() );
+		  );
+		
+		if(selected_var == 'dist2k3',
+			set(selected_setting,      vr_setup_d2k3);
+			set(selected_var_name,     'i_dist2_k3');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      -9);
+			set(selected_var_max,      +9);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_update_dist2() );
+		  );
+
+		if(selected_var == 'dist2k4',
+			set(selected_setting,      vr_setup_d2k4);
+			set(selected_var_name,     'i_dist2_k4');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      -9);
+			set(selected_var_max,      +9);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_update_dist2() );
+		  );
+
+		if(selected_var == 'vignette',
+			set(selected_setting,      vr_setup_vig2);
+			set(selected_var_name,     'webvr.mobilevr_lens_vign');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     1);
+			set(selected_var_min,      10);
+			set(selected_var_max,      200);
+			set(selected_var_round,    0);
+			set(selected_var_callback, vr_setup_change_headset(0) );
+		  );
+
+		if(selected_var == 'ca',
+			set(selected_setting,      vr_setup_cac2);
+			set(selected_var_name,     'webvr.mobilevr_lens_ca');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      -1.0);
+			set(selected_var_max,      +1.0);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_change_headset(0) );
+		  );
+		  
+		if(selected_var == 'overlap',
+			set(selected_setting,      vr_setup_olp2);
+			set(selected_var_name,     'webvr.mobilevr_lens_overlap');
+			set(selected_var_postfix,  '');
+			copy(selected_var_value,   get(selected_var_name));
+			set(selected_var_step,     0.01);
+			set(selected_var_min,      0.5);
+			set(selected_var_max,      2.0);
+			set(selected_var_round,    2);
+			set(selected_var_callback, vr_setup_change_headset(0) );
+		  );
+
+		if(selected_setting != null,
+			set(layer[get(selected_setting)].background, true);
+			if(%2 == true,
+				set(layer[vr_setup_btn1].y, get(layer[get(selected_setting)].y));
+				set(layer[vr_setup_btn2].y, get(layer[get(selected_setting)].y));
+			  ,
+				tween(layer[vr_setup_btn1].y, get(layer[get(selected_setting)].y));
+				tween(layer[vr_setup_btn2].y, get(layer[get(selected_setting)].y));
+			  );
+		  );
+	</action>
+
+
+	<action name="vr_setup_change_screen">
+		set(layer[vr_setup_dvn2].html, 'Custom');
+		set(layer[vr_setup_dvn2].css, calc('color:#FFFFFF;font-size:'+40*webvr_setup_scale+'px;font-weight:bold;'));
+		set(layer[vr_setup_siz2].css, calc('color:#FFFFFF;font-size:'+40*webvr_setup_scale+'px;font-weight:bold;'));
+	</action>
+
+
+	<action name="vr_setup_change_ondown">
+		copy(t0,timertick);
+		set(t1,0);
+		asyncloop(pressed,
+			copy(t2,timertick);
+			sub(dt,t2,t1);
+			if(dt GT 100,
+				copy(t1,t2);
+				sub(dt,t1,t0);
+				div(dt,1000);
+				Math.max(dt,1);
+				mul(dt,%1);
+				vr_setup_adjust(get(dt));
+			  );
+		  );
+	</action>
+
+
+	<action name="vr_setup_adjust">
+		if(selected_setting != null,
+			mul(change, selected_var_step, %1);
+			add(selected_var_value, change);
+			Math.max(selected_var_value, selected_var_min);
+			Math.min(selected_var_value, selected_var_max);
+			roundval(selected_var_value, get(selected_var_round));
+			tween(get(selected_var_name), get(selected_var_value), 0.1);
+			txtadd(layer[get(selected_setting)].html, get(selected_var_value), get(selected_var_postfix));
+			if(selected_var_callback != null, selected_var_callback());
+		  );
+	</action>
+
+
+	<action name="vr_setup_change_headset">
+		set(i_headset, 'Custom');
+		if(%1 != 0,
+			copy(i_fov, webvr.mobilevr_lens_fov);
+			roundval(i_fov, 1);
+			copy(i_dist, webvr.mobilevr_lens_dist);
+			roundval(i_dist, 2);
+			copy(i_dist2, webvr.mobilevr_lens_dist2);
+			copy(i_vig, webvr.mobilevr_lens_vign);
+			roundval(i_vig, 0);
+			copy(i_ca, webvr.mobilevr_lens_ca);
+			roundval(i_ca, 3);
+			copy(i_overlap, webvr.mobilevr_lens_overlap);
+			roundval(i_overlap, 2);
+			set(i_hsindex, -1);
+			copy(i_hscount, vrheadsets.headset.count);
+			for(set(i,0), i LT i_hscount, inc(i),
+				copy(hs, vrheadsets.headset[get(i)]);
+				if(i_overlap == hs.overlap AND i_fov == hs.fov AND i_dist == hs.dist AND i_dist2 == hs.dist2 AND i_ca == hs.ca AND i_vig == hs.vig , copy(i_hsindex, i); copy(i_headset, hs.caption); );
+			   );
+
+			if(%1 GT 0,
+				<!-- loop right -->
+				add(i_hsindex, 1);
+				if(i_hsindex GE i_hscount, set(i_hsindex,0));
+			  ,
+				<!-- loop left -->
+				sub(i_hsindex, 1);
+				if(i_hsindex LT 0, sub(i_hsindex,i_hscount,1));
+			  );
+
+			copy(hs, vrheadsets.headset[get(i_hsindex)]);
+			copy(i_headset, hs.caption);
+			copy(i_overlap, hs.overlap);
+			copy(i_fov,     hs.fov);
+			copy(i_dist,    hs.dist);
+			copy(i_dist2,   hs.dist2);
+			copy(i_ca,      hs.ca);
+			copy(i_vig,     hs.vig);
+		  );
+
+		copy(layer[vr_setup_hmd2].html, i_headset);
+		if(%1 != 0,
+			copy(webvr.mobilevr_lens_overlap, i_overlap);
+			copy(webvr.mobilevr_lens_fov, i_fov);
+			copy(webvr.mobilevr_lens_dist, i_dist);
+			copy(webvr.mobilevr_lens_dist2, i_dist2);
+			copy(webvr.mobilevr_lens_ca, i_ca);
+			copy(webvr.mobilevr_lens_vign, i_vig);
+			copy(layer[vr_setup_olp2].html, i_overlap);
+			copy(layer[vr_setup_fov2].html, i_fov);
+			copy(layer[vr_setup_dst2].html, i_dist);
+			
+			txtsplit(i_dist2, '|', i_dist2_k1, i_dist2_k2, i_dist2_k3, i_dist2_k4);
+			mul(i_dist2_k1,1);
+			mul(i_dist2_k2,10);
+			mul(i_dist2_k3,10);
+			mul(i_dist2_k4,10);
+			roundval(i_dist2_k1,2);
+			roundval(i_dist2_k2,2);
+			roundval(i_dist2_k3,2);
+			roundval(i_dist2_k4,2);
+			copy(layer[vr_setup_d2k1].html, i_dist2_k1);
+			copy(layer[vr_setup_d2k2].html, i_dist2_k2);
+			copy(layer[vr_setup_d2k3].html, i_dist2_k3);
+			copy(layer[vr_setup_d2k4].html, i_dist2_k4);
+			
+			copy(layer[vr_setup_cac2].html, i_ca);
+			copy(layer[vr_setup_vig2].html, i_vig);
+		  );
+	</action>
+
+</krpano>

BIN
public/krpano/plugins/webvr_cursor_80x80_17f.png


BIN
public/krpano/skin/masking.png


BIN
public/krpano/skin/vtourskin.png


Plik diff jest za duży
+ 1299 - 0
public/krpano/skin/vtourskin.xml


+ 447 - 0
public/krpano/tooltip.xml

@@ -0,0 +1,447 @@
+<krpano>
+    <!-- 1.20. 新热点模式 -->
+    <action name="addJQHotspot">
+        <!-- showlog(); -->
+        set(hsp_name,%1); 
+        set(hsp_type,%2); 
+        txtadd(iconUrl,'',%4);
+        txtreplace(iconUrl,'|',',');
+
+        <!-- trace('opentype::',%11); -->
+        if(%2 LE 1,
+             <!-- trace('id==',get(hsp_name),"::",get(iconUrl)); -->
+             set(hotspot[get(hsp_name)].type,'image');
+             set(hotspot[get(hsp_name)].url,get(iconUrl));
+         );
+        ifnot(%2 LE 1, set(hotspot[get(hsp_name)].type, 'text'));
+
+        <!-- 其他标签 (0,1,2)-->
+    
+        set(hotspot[get(hsp_name)].name,%1);
+        set(hotspot[get(hsp_name)].hotspottype,%2);
+        set(hotspot[get(hsp_name)].hotspottitle,%3);
+        set(hotspot[get(hsp_name)].hoverstatus,%9);
+        set(hotspot[get(hsp_name)].hotspotStyle,%10);
+        set(hotspot[get(hsp_name)].opentype,%11);
+        set(hotspot[get(hsp_name)].hotlink,%7);
+        set(hotspot[get(hsp_name)].ath,%5);
+        set(hotspot[get(hsp_name)].atv,%6);
+        set(hotspot[get(hsp_name)].visible,true);
+        set(hotspot[get(hsp_name)].alpha,1);
+        set(hotspot[get(hsp_name)].scale,1);
+  
+        set(hotspot[get(hsp_name)].autoalpha,false);
+        set(hotspot[get(hsp_name)].distorted,false);
+        set(hotspot[get(hsp_name)].border,false);
+        <!-- set(hotspot[get(hsp_name)].onclick,'js(__krfn.utils.linkopen(%7,%1)); '); -->
+        set(hotspot[get(hsp_name)].onclick,'js(__sdk.Tags.linkopen(%11,%1)); ');
+        <!-- set(hotspot[get(hsp_name)].ondown,dragJQhotspot(););
+        set(hotspot[get(hsp_name)].onup,js(console.log('0');__krfn.angle.updateHotSpotData(get(xml.scene),get(name),get(ath),get(atv)))); -->
+
+        txtsplit(%10,'|',fontSize,pos,isHover,borderColor,fillColor,textColor,isShowLine,isTextWrap,lineDirection,textDirection,textNumPerLine,duration,frameNumber,framewidth);
+        set(hotspot[get(hsp_name)].pos,pos);
+        txtadd(hotspot[get(hsp_name)].onloaded,"add_tooltip_label();add_tooltip_dot();");
+
+        if(%2 LE 2,
+            set(hotspot[get(hsp_name)].height,%8);
+            set(hotspot[get(hsp_name)].width,%8);
+            set(hotspot[get(hsp_name)].crop,'');
+        
+               
+                if(%2 == 0,
+                txtreplace(iconUrl,'.svg','.png');
+                <!-- trace('system::',get(iconUrl)); -->
+                set(hotspot[get(hsp_name)].url,get(iconUrl));
+                set(hotspot[get(hsp_name)].frameNumber,60);
+                
+                set(hotspot[get(hsp_name)].duration,1);
+                set(hotspot[get(hsp_name)].frameRate,calc(1.0 / 60));
+                set(hotspot[get(hsp_name)].framewidth,84);
+                );
+                if(%2 == 1,
+                set(hotspot[get(hsp_name)].url,get(iconUrl));
+                set(hotspot[get(hsp_name)].animatiedOn,0);
+                );
+                if(%2 == 2,
+                <!-- trace('ser_frame::',get(framewidth)); -->
+                set(hotspot[get(hsp_name)].duration, get(duration));
+                set(hotspot[get(hsp_name)].frameRate,calc(duration / frameNumber));
+                trace(calc('当前热点序列::' + get(hotspot[get(hsp_name)].hotspottitle)+'::duration::'+get(duration)+'frameNumber::'+get(frameNumber) +'frameRate::'+get(calc(duration / frameNumber))));
+                set(hotspot[get(hsp_name)].url,get(iconUrl));
+                set(hotspot[get(hsp_name)].framewidth,get(framewidth));
+                set(hotspot[get(hsp_name)].frameNumber,get(frameNumber));
+                );
+        );
+        
+        <!-- 个性化标签(3) -->
+        if(%2 == 3,    
+           
+            set(hotspot[get(hsp_name)].height,80);
+            set(hotspot[get(hsp_name)].width,1);
+            set(hotspot[get(hsp_name)].padding,0);
+            set(hotspot[get(hsp_name)].background,false);
+            txtadd(line,'<div style="background-color: ',get(borderColor),';width:1px;height:80px;"></div>');
+            copy(hotspot[get(hsp_name)].html,line);
+            <!-- txtadd(hotspot[get(hsp_name)].onloaded,"add_tooltip_label();add_tooltip_dot();"); -->
+            if(isShowLine == 1, 
+            txtadd(tooltipname, 'tooltip_', get(hsp_name)); 
+            txtadd(tooltipdot, 'tooldot_', get(hsp_name)); 
+            set(hotspot[get(hsp_name)].visible,false);
+            set(layer[get(tooltipname)].visible,false);
+            set(layer[get(tooltipdot)].visible,false);
+             
+            set_label_dir(get(hsp_name),get(lineDirection),0);
+            );
+           
+             if(isShowLine == 0, 
+                txtadd(tooltipname, 'tooltip_', get(hsp_name)); 
+                txtadd(tooltipdot, 'tooldot_', get(hsp_name)); 
+                <!-- set_label_dir(get(hsp_name),get(lineDirection),0); -->
+                set(hotspot[get(hsp_name)].width,0);
+                <!-- trace('隐藏标线::',get(tooltipdot)); -->
+                set(layer[get(tooltipname)].x,0);
+                set(layer[get(tooltipname)].y,0);
+                set(layer[get(tooltipname)].rotate,0);
+                set(hotspot[get(hsp_name)].visible,true);
+                set(layer[get(tooltipname)].visible,true);
+                set(layer[get(tooltipdot)].visible,false);
+             );  
+        );
+     
+        txtadd(hotspot[get(hsp_name)].onloaded,"make_hotsport_animation(get(framewidth),get(framewidth),get(frameRate));");
+        <!-- trace('last_add::',hotspot[get(hsp_name)].onloaded); -->
+        addhotspot(get(hsp_name));
+    </action>
+
+	<action name="make_hotsport_animation">
+    <!-- 1 square:(w/h) 2:imageW 3 imageH 4 frameRate -->
+       <!-- trace('imagewidth::',imagewidth,'::imageheight::',imageheight); -->
+        registerattribute(xframes, calc((imagewidth / %1) BOR 0));
+        registerattribute(yframes, calc((imageheight / %2) BOR 0)); 
+        registerattribute(frames, calc(xframes * yframes));
+        registerattribute(frame, 0); 
+        registerattribute(animatiedOn, 1); 
+        registerattribute(frameRate, %3);
+        <!-- trace('frameRate::',get(frameRate)); -->
+        set(crop, '0|0|%1|%2'); 
+        clearinterval(calc('crop_anim_' + name));
+        <!-- trace('frameRate',get(frameRate));  -->
+        if(%3 == '' OR frameRate == 0 OR isNaN(frameRate),
+        set(frameRate,calc(1.0 / 60));
+        <!-- trace('没有frameRate',get(calc(1.0 / 60)));
+        trace('没有frameRate-1',get(frameRate)); -->
+        );
+        <!-- trace('params::1::',%1,'::2::',%2,'::3::',%3,':frameRate:',get(frameRate));
+        trace('xframes1::',get(xframes),'::yframes1::',get(yframes)); -->
+   
+               
+        if(frameRate GE 0,
+        setinterval(
+            calc('crop_anim_' + name),
+            get(frameRate),
+            if(loaded, 
+                inc(frame); 
+               
+                <!-- trace('frame::',get(frame),'xframes2::',get(xframes),'::yframes2::',get(yframes)); -->
+                if(frame GE frames, if(onlastframe !== null, onlastframe() ); set(frame,0); );
+                mod(xpos,frame, xframes); 
+                div(ypos, frame, xframes);
+                Math.floor(ypos);
+                mul(xpos, %1);
+                mul(ypos, %2); 
+                calc(crop, xpos +'|' + ypos + '|%1|%2');
+ 
+                if(animatiedOn == 0, 
+                 calc(stopAniCrop,'0|0|'+imagewidth+'|'+imageheight +'|');
+                 set(crop, stopAniCrop);
+                );,
+                clearinterval(calc('crop_anim_' + name));
+            );
+        );
+        );   
+	</action>
+
+    <action name="add_tooltip_label">
+        txtadd(tooltipname, 'tooltip_', get(name)); 
+      
+        txtsplit(hotspotStyle,'|',fontSize,pos,isHover,borderColor,fillColor,textColor,isShowLine,isTextWrap,lineDirection,textDirection,textNumPerLine,duration,frameNumber);
+        txtadd(pName, get(name)); 
+        addlayer(get(tooltipname));
+        txtadd(layer[get(tooltipname)].parent, 'hotspot[', get(name), ']');
+        set(layer[get(tooltipname)].autowidth, true);
+        set(layer[get(tooltipname)].width,'prop');
+        set(layer[get(tooltipname)].autoheight,true); 
+        set(layer[get(tooltipname)].edge,center);
+        set(layer[get(tooltipname)].background,false);
+        set(layer[get(tooltipname)].pos,pos);
+        set(layer[get(tooltipname)].padding,0);
+        set(layer[get(tooltipname)].type,'html');
+        set(layer[get(tooltipname)].url,'%SWFPATH%/krpano/plugins/textfield.swf');
+        set(layer[get(tooltipname)].border,false);
+        set(layer[get(tooltipname)].align,center);
+        copy(layer[get(tooltipname)].hotlink, hotspot[get(name)].hotlink);
+        <!-- set(layer[get(tooltipname)].ondown,'dragJQlayer();'); -->
+        
+        set(layer[get(tooltipname)].onclick,JQlayerClick);
+        <!-- set(layer[get(tooltipname)].onup,js(console.log('1');__krfn.angle.updateHotSpotData(get(xml.scene),get(hsName),get(ath),get(atv)))); -->
+        <!-- set(hotspot[get(hsp_name)].onup,js(__krfn.angle.updateHotSpotData(get(xml.scene),get(name),get(ath),get(atv)))); -->
+        txtadd(labelCode, '<div style="display: flex; align-items: center; justify-content: center; position: relative; border: 1px solid ',get(borderColor),'; padding: 6px 10px; white-space: pre; border-radius: 5px; background: ',get(fillColor),'">','            <div style="text-align: left; font-size:',get(fontSize),'px; color: ',get(textColor),'; line-height: 1.4;">',get(hotspottitle),'</div>
+        </div>'); 
+        
+                                <!-- label方位 -->
+        if(get(hotspottype) LE 2,
+         copy(hoverstatus,hotspot[get(name)].hoverstatus); 
+         <!-- trace('hovering-label::',get(hoverstatus)); -->
+        <!-- delayedcall(0.1,
+            txtadd(tooltipname, 'tooltip_', get(name)); 
+            set_label_pos(get(tooltipname),get(pos));
+         ); -->
+          if(hoverstatus == 0,
+            delayedcall(0.5,
+            txtadd(tooltipname, 'tooltip_', get(name)); 
+            set_label_pos(get(tooltipname),get(pos));
+            );
+         );
+        if(hoverstatus == 1,
+            set(layer[get(tooltipname)].visible,false);
+         );
+          <!-- 2 hover  -->
+        if(hoverstatus == 2,
+            <!-- trace('测试'); -->
+           set(layer[get(tooltipname)].visible,false);
+            delayedcall(0.5,
+             txtadd(tooltipname, 'tooltip_', get(name)); 
+                set_label_pos(get(tooltipname),get(pos));
+                set(layer[get(tooltipname)].visible,false);
+            );
+            set(hotspot[get(name)].onhover,txtadd(tooltipname, 'tooltip_', get(name)); set(layer[get(tooltipname)].visible,true););
+            set(hotspot[get(name)].onout,
+             txtadd(tooltipname, 'tooltip_', get(name)); 
+             set(layer[get(tooltipname)].visible,false);
+            );
+         );
+       );
+
+        <!-- 个性化标签(3) -->
+        if(get(hotspottype) == 3,    
+           if(
+            isShowLine==1,
+            set(layer[get(tooltipname)].direction,get(lineDirection));
+            delayedcall(0.2,txtadd(tooltipname, 'tooltip_', get(name)); set_label_dir(get(tooltipname),get(layer[get(tooltipname)].direction),1); );
+          );
+        );
+        copy(layer[get(tooltipname)].html, labelCode);
+        
+            
+    </action>
+    <!-- <style name="tooltip_dot_bg" type="container" border-radius="50%" bgcolor="0xFFFFFF" bgalpha="0.9" height="20" width="20" keep="true" /> -->
+    <action name='add_tooltip_dot'>
+        txtadd(tooldot, 'tooldot_', get(name)); 
+        <!-- trace('hey::',get(borderColor)); -->
+
+        <!-- trace('add-dot-type::',get(name),'::',get(hotspottype)); -->
+        addlayer(get(tooldot));
+        txtadd(layer[get(tooldot)].parent, 'hotspot[', get(name), ']');
+        set(layer[get(tooldot)].width,10); 
+        set(layer[get(tooldot)].height,10); 
+        set(layer[get(tooldot)].padding,0); 
+       
+        set(layer[get(tooldot)].align,center);
+        set(layer[get(tooldot)].type,'text');
+        set(layer[get(tooldot)].background,false);
+        txtadd(dborderColor,'rgba(255,255,255,0.5)');
+        txtadd(dot,'<div style="background-color: ',get(borderColor),';width:10px;height:10px;"></div>');
+        copy(layer[get(tooldot)].html,dot);
+        set(layer[get(tooldot)].backgroundcolor,get(borderColor)); 
+        set(layer[get(tooldot)].backgroundalpha,0.9); 
+        set(layer[get(tooldot)].bgroundedge,5);
+        set(layer[get(tooldot)].onclick,JQlayerClick);
+        <!-- set(layer[get(tooldot)].ondown,'dragJQlayer();'); -->
+        set(layer[get(tooldot)].visible,false);
+        <!-- set(layer[get(tooldot)].onup,js(console.log('2');__krfn.angle.updateHotSpotData(get(xml.scene),get(hsName),get(ath),get(atv)))); -->
+
+        <!-- 个性化标签(3) -->
+        if(get(hotspottype) == 3,    
+    
+            if(isShowLine ==1,set(layer[get(tooldot)].visible,true);set_label_dir(get(tooldot),get(lineDirection),2););
+            if(isShowLine ==0,set(layer[get(tooldot)].visible,false););
+                  
+        );
+
+    </action>
+    <action name='set_label_dir'>
+     txtadd(dirItem,'',%1);
+     txtadd(lineDirection,'',%2);
+     txtadd(dir,'',%3);
+     <!-- trace('get-lineDirection::',%2); -->
+     <!-- trace('set_label_dir::1::',get(dirItem),'::2::',get(lineDirection),'::3::',get(dir)); -->
+     if(
+        get(dir)==1,
+        <!-- trace('set_label_dir::1::',get(dirItem),'::2::',get(lineDirection),'::3::',get(dir)); -->
+        copy(labelWidth,layer[get(dirItem)].width);
+        copy(labelHeight,layer[get(dirItem)].height);
+  
+  
+     );
+
+        if(
+             get(lineDirection) == 'right-top',
+            if(get(dir)==0,set(hotspot[get(dirItem)].rotate,35));
+            if(get(dir)==1,add(allHeight,labelHeight,80);div(allHeight,2);mul(allHeight,-1);set(layer[get(dirItem)].rotate,0);set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,get(allHeight));set(layer[get(dirItem)].rotate,-35););
+            if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,40););
+        );
+        if(
+             get(lineDirection) == 'right-center',
+             if(get(dir)==0,set(hotspot[get(dirItem)].rotate,90););
+             if(get(dir)==1,
+                set(layer[get(dirItem)].rotate,-90);
+               add(allWidth,labelWidth,80);
+                div(allWidth,2);
+                mul(allWidth,-1);
+                trace('allWidth::',get(allWidth));
+                set(layer[get(dirItem)].x,0);
+                set(layer[get(dirItem)].y,get(allWidth));
+                );
+           
+             if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,40););
+        );
+        if(
+             get(lineDirection) == 'right-bottom',
+            if(get(dir)==0,set(hotspot[get(dirItem)].rotate,-35));
+            if(get(dir)==1,add(allHeight,labelHeight,80);div(allHeight,2);mul(allHeight,1);set(layer[get(dirItem)].rotate,0);set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,get(allHeight));set(layer[get(dirItem)].rotate,35););
+           if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,-40););
+        );
+        if(
+             get(lineDirection) == 'center-top',
+            if(get(dir)==0,
+            set(hotspot[get(dirItem)].rotate,0);
+            );
+            if(get(dir)==1,add(allHeight,labelHeight,80);div(allHeight,2);mul(allHeight,-1);set(layer[get(dirItem)].rotate,0);set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,get(allHeight)););
+            if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,40););
+        );
+        if(get(lineDirection) == 'center-bottom',
+            if(get(dir)==0,set(hotspot[get(dirItem)].rotate,0));
+            if(get(dir)==1,add(allHeight,labelHeight,80);div(allHeight,2);mul(allHeight,1);
+               set(layer[get(dirItem)].rotate,0);
+               set(layer[get(dirItem)].x,0);
+               set(layer[get(dirItem)].y,get(allHeight));     
+              );
+            if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,-40););
+        );
+        if( get(lineDirection) == 'left-top',
+        <!-- newx = distance * Math.cos(direction) + x
+        newy = distance * Math.sin(direction) + y -->
+            <!-- showlog(); -->
+            if(get(dir)==0,set(hotspot[get(dirItem)].rotate,-35));
+            if(get(dir)==1,
+            add(allHeight,labelHeight,80);
+            div(allHeight,2);mul(allHeight,-1);
+            set(rr,calc((Math.PI / 180) * -35));
+            <!-- set(newY,calc(allHeight * Math.asin(rr))); -->
+            trace('newY',allHeight);
+            set(layer[get(dirItem)].rotate,0);
+            set(layer[get(dirItem)].x,0);
+            set(layer[get(dirItem)].y,get(allHeight));
+            set(layer[get(dirItem)].rotate,35););
+            if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,40););
+        );
+        if(
+             get(lineDirection) == 'left-center',
+             if(get(dir)==0,set(hotspot[get(dirItem)].rotate,90));
+             
+             if(get(dir)==1,
+                set(layer[get(dirItem)].rotate,-90);
+               add(allWidth,labelWidth,80);
+                div(allWidth,2);
+                trace('allWidth::',get(allWidth));
+                set(layer[get(dirItem)].x,0);
+                set(layer[get(dirItem)].y,get(allWidth));
+                );
+             if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,-40););
+        );
+        if(
+            get(lineDirection) == 'left-bottom',
+            if(get(dir)==0,set(hotspot[get(dirItem)].rotate,35));
+            if(get(dir)==1,add(allHeight,labelHeight,80);div(allHeight,2);mul(allHeight,1);set(layer[get(dirItem)].rotate,0);set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,get(allHeight));set(layer[get(dirItem)].rotate,-35););
+            if(get(dir)==2,set(layer[get(dirItem)].x,0);set(layer[get(dirItem)].y,-40););
+
+        );
+          
+          if(get(dir)==0, set(hotspot[get(dirItem)].visible,true););
+          if(get(dir)==1, set(layer[get(dirItem)].visible,true););
+          if(get(dir)==2, set(layer[get(dirItem)].visible,true););
+
+    </action>
+
+    <action name='set_label_pos'>
+        <!-- label方位 -->
+       <!-- showlog(); -->
+       set(posName,%1);
+       set(pos,%2);
+       copy(hp,posName);
+       txtreplace(hp,'tooltip_','');
+
+       copy(hwidth, hotspot[get(hp)].width);
+       copy(hheight, hotspot[get(hp)].height);
+       <!-- trace('hwidth::',get(hwidth)); -->
+       copy(lwidth, layer[get(posName)].width);
+       copy(lheight, layer[get(posName)].height);
+       trace(calc('当前热点pos::' + get(pos)));
+       trace(calc('当前热点动态宽::' + get(hp)+"::"),get(lwidth));
+       trace(calc('当前热点动态高::' + get(hp)+"::"),get(lheight));
+
+        if(
+            pos == 'top',
+            add(all,lheight,hheight);
+            div(dpy,all,2); 
+            add(lastPy,dpy,5);
+            <!-- trace('dpy::',dpy); -->
+            mul(lastPy, -1);
+            set(layer[get(posName)].align,center);
+            set(layer[get(posName)].y,get(lastPy));
+            set(layer[get(posName)].x,0);
+        );
+         if(
+            pos == 'bottom',
+            add(all,lheight,hheight);
+            div(dpy,all,2); 
+            add(lastPy,dpy,5);
+            mul(lastPy, 1);
+            set(layer[get(posName)].align,center);
+            set(layer[get(posName)].y,get(lastPy));
+            set(layer[get(posName)].x,0);
+        );
+        if(
+            pos == 'left',
+            add(all,lwidth,hwidth);
+            div(dpx,all,2); 
+            add(lastPx,dpx,10);
+            mul(lastPx, -1);
+            set(layer[get(posName)].align,center);
+            set(layer[get(posName)].x,get(lastPx));
+            set(layer[get(posName)].y,0);
+        );
+        if(
+            pos == 'right',
+            add(all,lwidth,hwidth);
+            div(dpx,all,2); 
+            add(lastPx,dpx,10);
+            mul(lastPx, 1);
+            set(layer[get(posName)].align,center);
+            set(layer[get(posName)].x,get(lastPx));
+            set(layer[get(posName)].y,0);
+        );
+    </action>
+
+ 
+
+<action name='JQlayerClick'>
+       txtadd(clickName, '', get(name)); 
+       txtreplace(clickName, 'tooltip_', ''); 
+       txtreplace(clickName, 'tooldot_', ''); 
+       <!-- trace('opentype::',get(hotspot[get(clickName)].opentype));
+       trace('clickName::',get(clickName)); -->
+       js(__sdk.Tags.linkopen(get(hotspot[get(clickName)].opentype),get(clickName)));
+</action>
+
+</krpano>

+ 317 - 0
public/krpano/tour.xml

@@ -0,0 +1,317 @@
+<krpano version="1.21" title="Virtual Tour">
+
+  <include url="%SWFPATH%/krpano/skin/vtourskin.xml" />
+
+  <!-- customize skin settings: maps, gyro, webvr, thumbnails, tooltips, layout, design, ... -->
+  <skin_settings maps="false"
+    maps_type="google"
+    maps_bing_api_key=""
+    maps_google_api_key=""
+    maps_zoombuttons="false"
+    maps_loadonfirstuse="true"
+    gyro="true"
+    gyro_keeplookingdirection="false"
+    webvr="true"
+    webvr_keeplookingdirection="true"
+    webvr_prev_next_hotspots="true"
+    autotour="false"
+    littleplanetintro="false"
+    followmousecontrol="false"
+    title="true"
+    thumbs="true"
+    thumbs_width="120" thumbs_height="80" thumbs_padding="10" thumbs_crop="0|40|240|160"
+    thumbs_opened="false"
+    thumbs_text="false"
+    thumbs_dragging="true"
+    thumbs_onhoverscrolling="false"
+    thumbs_scrollbuttons="false"
+    thumbs_scrollindicator="false"
+    thumbs_loop="false"
+    tooltips_buttons="false"
+    tooltips_thumbs="false"
+    tooltips_hotspots="false"
+    tooltips_mapspots="false"
+    deeplinking="false"
+    loadscene_flags="MERGE"
+    loadscene_blend="OPENBLEND(0.5, 0.0, 0.75, 0.05, linear)"
+    loadscene_blend_prev="SLIDEBLEND(0.5, 180, 0.75, linear)"
+    loadscene_blend_next="SLIDEBLEND(0.5,   0, 0.75, linear)"
+    loadingtext="loading..."
+    layout_width="100%"
+    layout_maxwidth="814"
+    controlbar_width="-24"
+    controlbar_height="40"
+    controlbar_offset="20"
+    controlbar_offset_closed="-40"
+    controlbar_overlap.no-fractionalscaling="10"
+    controlbar_overlap.fractionalscaling="0"
+    design_skin_images="vtourskin.png"
+    design_bgcolor="0x2D3E50"
+    design_bgalpha="0.8"
+    design_bgborder="0"
+    design_bgroundedge="1"
+    design_bgshadow="0 4 10 0x000000 0.3"
+    design_thumbborder_bgborder="3 0xFFFFFF 1.0"
+    design_thumbborder_padding="2"
+    design_thumbborder_bgroundedge="0"
+    design_text_css="color:#FFFFFF; font-family:Arial;"
+    design_text_shadow="1"
+  />
+
+  <!--
+        For an alternative skin design either change the <skin_settings> values
+        from above or optionally include one of the predefined designs from below.
+    -->
+  <!-- <include url="skin/vtourskin_design_flat_light.xml"  /> -->
+  <!-- <include url="skin/vtourskin_design_glass.xml"       /> -->
+  <!-- <include url="skin/vtourskin_design_ultra_light.xml" /> -->
+  <!-- <include url="skin/vtourskin_design_117.xml"         /> -->
+  <!-- <include url="skin/vtourskin_design_117round.xml"    /> -->
+  <!-- <include url="skin/vtourskin_design_black.xml"       /> -->
+  <!-- startup action - load the first scene -->
+
+  <action name="startup" autorun="onstart">
+    if(startscene === null OR !scene[get(startscene)], copy(startscene,scene[3].name); );
+    loadscene(get(startscene), null, MERGE);
+
+    if(startactions !== null, startactions() );
+
+  </action>
+
+
+  <scene name="scene_fd720_H1d5v4Jkw" title="fd720_H1d5v4Jkw" onstart=""
+    thumburl="%CURRENTXML%../fd720_H1d5v4Jkw/vtour/panos/fd720_H1d5v4Jkw.tiles/thumb.jpg"
+    lat="22.34274422" lng="114.18975258" alt="118.68" heading="0.0">
+
+    <control bouncinglimits="calc:image.cube ? true : false" />
+
+    <view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70"
+      fovmax="140" limitview="auto" />
+
+    <preview url="%CURRENTXML%../fd720_H1d5v4Jkw/vtour/panos/fd720_H1d5v4Jkw.tiles/preview.jpg" />
+
+    <image>
+      <cube
+        url="%CURRENTXML%../fd720_H1d5v4Jkw/vtour/panos/fd720_H1d5v4Jkw.tiles/%s/l%l/%v/l%l_%s_%v_%h.jpg"
+        multires="512,640,1152,2304,4608" />
+    </image>
+    <!-- 多边形热点 -->
+
+    <hotspot
+      name="eee"
+      keep="false"
+      visible="true"
+      enabled="true"
+      handcursor="true"
+      zorder=""
+      capture="true"
+      blendmode="normal"
+      style=""
+      alpha="1"
+      autoalpha="false"
+      fillcolor="0xFF6970" fillcolorover="0xFFFFFF"
+      fillalpha="0.5" fillalphahover="0.1"
+      borderwidth="3" borderwidthhover="4.0"
+      bordercolor="0xFFFFFF" bordercolorhover="0xff7900"
+      borderalpha="1" borderalphahover="0.8"
+      fadeintime="0.15" fadeincurve="1.1"
+      fadeouttime="0.3" fadeoutcurve="0.7"
+      onover=""
+      onhover=""
+      onout=""
+      onup=""
+      onclick="js(test())"
+      onloaded=""
+      ondown="">
+      <point ath="-26.27" atv="19.42" />
+      <point ath="46.57" atv="14.42" />
+      <point ath="64.61" atv="18.14" />
+      <point ath="65.69" atv="33.87" />
+      <point ath="76.83" atv="36.03" />
+      <point ath="61.01" atv="58.68" />
+      <point ath="19.58" atv="43.14" />
+      <point ath="-16.50" atv="41.21" />
+      <point ath="-33.62" atv="67.03" />
+      <point ath="-62.68" atv="53.41" />
+      <point ath="-62.39" atv="34.18" />
+
+
+    </hotspot>
+
+  </scene>
+  <scene name="scene_fd720_yT31ElTQe" title="fd720_yT31ElTQe" onstart=""
+    thumburl="%CURRENTXML%../fd720_yT31ElTQe/vtour/panos/fd720_yT31ElTQe.tiles/thumb.jpg"
+    lat="22.34262936" lng="114.18955128" alt="178.93" heading="0.0">
+
+    <control bouncinglimits="calc:image.cube ? true : false" />
+
+    <view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70"
+      fovmax="140" limitview="auto" />
+
+    <preview url="%CURRENTXML%../fd720_yT31ElTQe/vtour/panos/fd720_yT31ElTQe.tiles/preview.jpg" />
+
+    <image>
+      <cube
+        url="%CURRENTXML%../fd720_yT31ElTQe/vtour/panos/fd720_yT31ElTQe.tiles/%s/l%l/%v/l%l_%s_%v_%h.jpg"
+        multires="512,640,1152,2304,4608" />
+    </image>
+
+  </scene>
+  <scene name="scene_fd720_PxVZ0tc3O" title="fd720_PxVZ0tc3O" onstart=""
+    thumburl="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_PxVZ0tc3O/vtour/panos/fd720_PxVZ0tc3O.tiles/thumb.jpg"
+    lat="22.34251953" lng="114.18946114" alt="149.18" heading="0.0">
+
+    <control bouncinglimits="calc:image.cube ? true : false" />
+
+    <view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70"
+      fovmax="140" limitview="auto" />
+
+    <preview
+      url="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_PxVZ0tc3O/vtour/panos/fd720_PxVZ0tc3O.tiles/preview.jpg" />
+
+    <image>
+      <cube
+        url="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_PxVZ0tc3O/vtour/panos/fd720_PxVZ0tc3O.tiles/%s/l%l/%v/l%l_%s_%v_%h.jpg"
+        multires="512,640,1152,2304,4608" />
+    </image>
+
+    <!-- 
+    <view stereographic="true"
+      fisheye="1.0"
+      fov="85"
+      fovtype="VFOV"
+      fovmax="150"
+      hlookat="-32.63"
+      vlookat="0"
+    /> -->
+
+    <!-- 多边形热点 -->
+
+    <hotspot
+      name="eee"
+      keep="false"
+      visible="true"
+      enabled="true"
+      handcursor="true"
+      zorder=""
+      capture="true"
+      blendmode="normal"
+      style=""
+      alpha="0"
+      autoalpha="false"
+      fillcolor="0xFF6970" fillcolorhover="0xFFFFFF"
+      fillalpha="0.5" fillalphahover="0.1"
+      borderwidth="3" borderwidthhover="4.0"
+      bordercolor="0xFFFFFF" bordercolorhover="0xff7900"
+      borderalpha="1" borderalphahover="0.8"
+      fadeintime="0.15" fadeincurve="1.1"
+      fadeouttime="0.3" fadeoutcurve="0.7"
+      onover=""
+      onhover="js(onHotspotHover())"
+      onout="js(onHotspotOut())"
+      onup=""
+      onclick="js(enterFDKK())"
+      onloaded=""
+      ondown="">
+      <point ath="-17.98" atv="29.20" />
+      <point ath="25.12" atv="27.74" />
+      <point ath="44.42" atv="46.64" />
+      <point ath="-29.71" atv="49.60" />
+
+
+    </hotspot>
+  </scene>
+
+  <!-- <events onloadcomplete="normalview();" /> -->
+  <!-- <action name="normalview">
+    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.limitview, lookto);
+    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, on);
+    copy(view.limitview, lp_limitview);
+    set(view.vlookatmin, null);
+    set(view.vlookatmax, null);
+    tween(view.hlookat|view.vlookat|view.fov|view.distortion, calc('5.685878490542688|
+    27.599464844622442 |' + lp_fov + '|' + 0.0),
+    3.0, easeOutQuad,
+    set(control.usercontrol, all);
+    tween(view.fovmax, get(lp_fovmax));
+    );
+    );
+    );
+    );
+  </action> -->
+
+  <!-- <autorotate enabled="true"
+    waittime="0.5"
+    speed="-5.0"
+    horizon="0.0"
+    tofov="90.0"
+  /> -->
+
+
+  <scene name="scene_fd720_F3Qm1yzlU" title="fd720_F3Qm1yzlU" onstart=""
+    thumburl="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_F3Qm1yzlU/vtour/panos/fd720_F3Qm1yzlU.tiles/thumb.jpg"
+    lat="22.34255478" lng="114.18954614" alt="121.18" heading="0.0">
+
+    <control bouncinglimits="calc:image.cube ? true : false" />
+
+    <view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70"
+      fovmax="140" limitview="auto" />
+
+    <preview
+      url="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_F3Qm1yzlU/vtour/panos/fd720_F3Qm1yzlU.tiles/preview.jpg" />
+
+    <image>
+      <cube
+        url="https://eurs3.4dkankan.com/720yun_fd_manage/fd720_F3Qm1yzlU/vtour/panos/fd720_F3Qm1yzlU.tiles/%s/l%l/%v/l%l_%s_%v_%h.jpg"
+        multires="512,640,1152,2304,4608" />
+    </image>
+    <!-- 多边形热点 -->
+
+    <hotspot
+      name="eee"
+      keep="false"
+      visible="true"
+      enabled="true"
+      handcursor="true"
+      zorder=""
+      capture="true"
+      blendmode="normal"
+      style=""
+      alpha="0"
+      autoalpha="false"
+      fillcolor="0xFF6970" fillcolorhover="0xFFFFFF"
+      fillalpha="0.5" fillalphahover="0.1"
+      borderwidth="3" borderwidthhover="4.0"
+      bordercolor="0xFFFFFF" bordercolorhover="0xff7900"
+      borderalpha="1" borderalphahover="0.8"
+      fadeintime="0.15" fadeincurve="1.1"
+      fadeouttime="0.3" fadeoutcurve="0.7"
+      onover=""
+      onhover="js(onHotspotHover())"
+      onout="js(onHotspotOut())"
+      onup=""
+      onclick="js(enterFDKK())"
+      onloaded=""
+      ondown="">
+      <point ath="-21.36" atv="15.36" />
+      <point ath="28.84" atv="14.23" />
+      <point ath="37.79" atv="17.68" />
+      <point ath="38.65" atv="33.40" />
+      <point ath="39.95" atv="38.91" />
+      <point ath="-35.90" atv="37.34" />
+      <point ath="-36.91" atv="23.09" />
+
+
+    </hotspot>
+  </scene>
+</krpano>

+ 44 - 47
src/App.vue

@@ -4,7 +4,7 @@
   </template> -->
   <div>
     <Opening @done="onOpeningDone" @show-step="isHomePage = true" />
-    <Homepage :show="isHomePage" @close="handleCloseAndGoHomePage" />
+    <Homepage :show="isHomePage" :showKrpano="showKrpano" @close="handleCloseAndGoHomePage" />
     <Logo :id="currentSceneId" />
     <RightMenu @toggle-menu="handleNavi" @change-scene="handleChangeScene" />
     <Container :url="currentScene"></Container>
@@ -12,76 +12,73 @@
   </div>
 </template>
 <script setup>
-import { onBeforeMount, onMounted, provide, ref, watchEffect } from 'vue';
-import Logo from './components/Logo.vue';
-import RightMenu from './components/RightMenu.vue';
-import Container from './components/Container.vue';
-import NavigationBar from './components/NavigationBar.vue';
-import Homepage from './components/Home.vue';
-import Opening from './components/Opening.vue';
+import { onBeforeMount, onMounted, provide, ref, watchEffect } from "vue";
+import Logo from "./components/Logo.vue";
+import RightMenu from "./components/RightMenu.vue";
+import Container from "./components/Container.vue";
+import NavigationBar from "./components/NavigationBar.vue";
+import Homepage from "./components/Home.vue";
+import Opening from "./components/Opening.vue";
 // import NoMobile from './components/Nomobile.vue';
-import MobileDetect from 'mobile-detect';
-
-import config from './config.json'
-const data = ref([])
-const isMo = ref(false)
-const isOpening = ref(false)
-const isHomePage = ref(true)
+import MobileDetect from "mobile-detect";
 
+import config from "./config.json";
+const data = ref([]);
+const isMo = ref(false);
+const isOpening = ref(false);
+const isHomePage = ref(true);
+const showKrpano = ref(false);
 
 const md = new MobileDetect(window.navigator.userAgent);
-data.value = config
-provide('data', data)
-provide('isMo', isMo)
-const navi = ref(false)
-const currentScene = ref('')
-const currentSceneId = ref('home')
+data.value = config;
+provide("data", data);
+provide("isMo", isMo);
+const navi = ref(false);
+const currentScene = ref("");
+const currentSceneId = ref("home");
 
 const handleNavi = () => {
-  navi.value = !navi.value
-  console.log('navi', navi.value)
-}
+  navi.value = !navi.value;
+  console.log("navi", navi.value);
+};
 const onOpeningDone = () => {
-  isOpening.value = true
-
-}
+  isOpening.value = true;
+  showKrpano.value = true;
+};
 
 onMounted(() => {
   if (md.mobile()) {
     // console.log('isMo')
-    isMo.value = true
-    document.body.classList.add('isMo')
-  
+    isMo.value = true;
+    document.body.classList.add("isMo");
+
     // return
   }
 
-  const scenes = Array.from(data.value).find(item => item.id === 'home');
-  currentScene.value = scenes.url
-
+  const scenes = Array.from(data.value).find((item) => item.id === "home");
+  currentScene.value = scenes.url;
 });
 
 const handleChangeScene = (item, isHome) => {
   if (!isHome) {
-    isHomePage.value = false
+    isHomePage.value = false;
   } else {
-    isHomePage.value = true
+    isHomePage.value = true;
   }
 
-  console.log('handleChangeScene', item, isHome)
-  currentScene.value = item.url
-  currentSceneId.value = item.id
-}
+  console.log("handleChangeScene", item, isHome);
+  currentScene.value = item.url;
+  currentSceneId.value = item.id;
+};
 const handleCloseAndGoHomePage = () => {
-  console.log('handleCloseAndGoHomePage')
+  console.log("handleCloseAndGoHomePage");
   const first = config[0];
-  isHomePage.value = false
-  currentScene.value = first.url
-  currentSceneId.value = first.id
-}
-
-
+  isHomePage.value = false;
+  currentScene.value = first.url;
+  currentSceneId.value = first.id;
+};
 </script>
 <style lang="sass">
 
 @--swiper-theme-color:#fff
-</style>
+</style>

+ 123 - 43
src/components/Home.vue

@@ -1,57 +1,137 @@
 <template>
-
-    <div class="homepage" v-if="show">
-        <div class="clickable" @click="emits('close')"></div>
-    </div>
-
-
+  <div class="homepage" v-if="show">
+    <!-- <div class="clickable" @click="emits('close')"></div> -->
+    <div id="kr_pano" style="width: 100vw; height: 100vh"></div>
+  </div>
 </template>
 <script setup>
-defineProps({
-    show: {
-        type: Boolean,
-        default: () => true
+import { onMounted, ref, onActivated, watch, nextTick } from "vue";
+const krpanoPath = ref(import.meta.env.VITE_KRPANO_DIR);
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: () => true,
+  },
+  showKrpano: {
+    type: Boolean,
+    default: () => false,
+  },
+});
+watch(
+  () => props.show,
+  (val) => {
+    if (val) {
+      nextTick(() => {
+        initKrpano();
+      });
+    } else {
     }
-})
+  }
+);
+watch(
+  () => props.showKrpano,
+  (val) => {
+    if (val) {
+      nextTick(() => {
+        initKrpano();
+      });
+    } else {
+    }
+  }
+);
+const emits = defineEmits(["close"]);
+onActivated(() => {});
+let krpano = null;
+let isHover = false;
+const hanlderEvent = () => {
+  window.enterFDKK = () => {
+    removepano("kr_pano");
+    isHover = false;
+    emits("close");
+  };
+  //完成加载
+  window.LoadedScene = () => {
+    setTimeout(() => {
+      krpano.set("view.hlookat", 5.685878490542688);
+      krpano.set("view.vlookat", 27.599464844622442);
+    }, 0);
+  };
+  window.onHotspotOut = () => {
+    // krpano.set("hotspot[eee].fillcolor", "0xFF6970");
+    // isHover = false;
+  };
+  window.onHotspotHover = () => {
+    // if (!isHover) {
+    //   isHover = true;
+    //   krpano.set("hotspot[eee].fillcolor", "0xFFFFFF");
+    // }
+  };
+};
+const initKrpano = () => {
+  embedpano({ xml: `${krpanoPath.value}tour.xml?x=${new Date().getTime()}`, target: "kr_pano", id: "krpanoSWFObject", passQueryParameters: true, onready: krpano_onready_callback });
+  hanlderEvent();
+};
+
+const krpano_onready_callback = (krpano_interface) => {
+  krpano = krpano_interface;
+  window.krpano = krpano;
+};
 
-const emits = defineEmits(['close'])
+const track_mouse_interval_callback = () => {
+  var mx = krpano.get("mouse.x");
+  var my = krpano.get("mouse.y");
+  var pnt = krpano.screentosphere(mx, my);
+  var h = pnt.x;
+  var v = pnt.y;
 
+  console.error('x="' + mx + '" y="' + my + '" ath="' + h.toFixed(2) + '" atv="' + v.toFixed(2) + '"');
+};
+
+const track_mouse = () => {
+  krpano.set("autorotate.enabled", false);
+  krpano.call("hotspotClicked");
+  track_mouse_interval_callback();
+};
+onMounted(() => {
+  // initKrpano();
+});
 </script>
-<style style="scss">
+<style lang="scss">
 .homepage {
+  width: 100%;
+  height: 100%;
+  // background-image: url("/src/assets/shouye.png");
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  position: absolute;
+  overflow: hidden;
+  z-index: 2;
+  top: 0;
+  left: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  user-select: none;
+  #pano {
     width: 100%;
     height: 100%;
-    background-image: url('/src/assets/shouye.png');
-    background-position: center center;
-    background-repeat: no-repeat;
-    background-size: cover;
-    position: absolute;
-    overflow: hidden;
-    z-index: 2;
-    top: 0;
-    left: 0;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    user-select: none;
-
-    .clickable {
-        width: 52vw;
-        height: 65vh;
-        margin-top: 12vh;
-        margin-right: 2vw;
-        margin-right: 4vw;
-        cursor: pointer;
-        /* background: rgba(0, 0, 0, 0.5); */
-        transform: skew(-5deg, -5deg);
-    }
-
+  }
+  .clickable {
+    width: 52vw;
+    height: 65vh;
+    margin-top: 12vh;
+    margin-right: 2vw;
+    margin-right: 4vw;
+    cursor: pointer;
+    /* background: rgba(0, 0, 0, 0.5); */
+    transform: skew(-5deg, -5deg);
+  }
 }
 
 .isMo {
-    .homepage {
-        object-fit: scale-down;
-        
-    }
+  .homepage {
+    object-fit: scale-down;
+  }
 }
-</style>
+</style>

+ 91 - 89
src/components/Opening.vue

@@ -1,116 +1,118 @@
 <template>
-    <Teleport to="body">
-        <view class="video-viewer" v-if="isShowVideo">
-            <video :playsinline="isMo"
-                :src="isMo ? 'https://eurs3.4dkankan.com/showcase/hklongxiang/video/opening-new.mp4' : 'https://eurs3.4dkankan.com/showcase/hklongxiang/video/opening-new.mp4'"
-                muted autoplay @play="onVideoPlaying" @ended="onVideoEnd">
-            </video>
-            <div v-if="showStepper" class="step-in" @click="closeVideo"> 跳過</div>
-            <div class="mo_b"></div>
-        </view>
-    </Teleport>
+  <Teleport to="body">
+    <view class="video-viewer" v-if="isShowVideo">
+      <video
+        :playsinline="isMo"
+        :src="isMo ? 'https://eurs3.4dkankan.com/showcase/hklongxiang/video/opening-new.mp4' : 'https://eurs3.4dkankan.com/showcase/hklongxiang/video/opening-new.mp4'"
+        autoplay
+        controls
+        @play="onVideoPlaying"
+        @ended="onVideoEnd"
+      ></video>
+      <div v-if="showStepper" class="step-in" @click="closeVideo">跳過</div>
+      <div class="mo_b"></div>
+    </view>
+  </Teleport>
 </template>
 <script setup>
-import { ref, onMounted, inject } from 'vue';
+import { ref, onMounted, inject } from "vue";
 const isShowVideo = ref(true);
 const showStepper = ref(false);
 const isMo = inject("isMo");
 var showTimer;
-const emits = defineEmits(['done', 'show-step']);
+const emits = defineEmits(["done", "show-step"]);
 
 const isWeixinBrowser = () => {
-    var ua = navigator.userAgent.toLowerCase();
-    return (/micromessenger/.test(ua)) ? true : false;
-}
-
+  var ua = navigator.userAgent.toLowerCase();
+  return /micromessenger/.test(ua) ? true : false;
+};
 
 const closeVideo = () => {
-    isShowVideo.value = false
-    emits('done')
-}
+  isShowVideo.value = false;
+  emits("done");
+};
 onMounted(() => {
-    if (isWeixinBrowser()) {
-        closeVideo();
-    }
-
-})
+  if (isWeixinBrowser()) {
+    closeVideo();
+  }
+  // closeVideo()
+});
 const onVideoPlaying = () => {
-    showTimer && clearTimeout(showTimer);
-    showTimer = setTimeout(() => {
-        showStepper.value = true
-        emits('show-step')
-    }, 3000);
-
-}
+  showTimer && clearTimeout(showTimer);
+  showTimer = setTimeout(() => {
+    showStepper.value = true;
+    emits("show-step");
+  }, 3000);
+};
 const onVideoEnd = () => {
-    emits('done')
-    closeVideo()
-}
+  emits("done");
+  closeVideo();
+};
 </script>
 <style lang="scss">
 .video-viewer {
-    position: fixed;
-    top: 0;
-    left: 0;
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 1000000;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 1);
+  .step-in {
+    background: rgba(0, 0, 0, 0.6);
+    position: absolute;
+    right: 30px;
+    top: 30px;
+    padding: 10px 30px;
+    border-radius: 20px;
+    cursor: pointer;
     z-index: 1000000;
+    color: white;
+  }
+
+  video {
     width: 100%;
     height: 100%;
-
-    .step-in {
-        background: rgba(0, 0, 0, 0.6);
-        position: absolute;
-        right: 30px;
-        top: 30px;
-        padding: 10px 30px;
-        border-radius: 20px;
-        cursor: pointer;
-        z-index: 1000000;
-        color: white;
-    }
-
-    video {
-        width: 100%;
-        height: 100%;
-        top: 0;
-        left: 0;
-        object-fit: fill;
-    }
+    top: 0;
+    left: 0;
+    object-fit: fill;
+  }
 }
 
 .isMo {
-    .video-viewer {
-        .mo_b {
-            background: rgba(0, 0, 0, 0.8);
-            filter: blur(2px);
-            position: absolute;
-            width: 100%;
-            height: 100%;
-            z-index: 1;
-            display: block;
-            top: 0;
-            left: 0;
-        }
-
-        video {
-            object-fit: scale-down;
-            z-index: 1001;
-            position: absolute;
-        }
+  .video-viewer {
+    .mo_b {
+      background: rgba(0, 0, 0, 0.8);
+      filter: blur(2px);
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      z-index: 1;
+      display: block;
+      top: 0;
+      left: 0;
     }
 
-    .step-in {
-        bottom: 80px;
-        top: initial;
-        color: white;
-        background: rgba(0, 0, 0, 1);
-        transform: translateX(-50%);
-        left: 50%;
-        display: inline-block;
-        text-align: center;
-        position: fixed;
-        padding: 10px;
-        width: 60px;
-        z-index: 10000;
+    video {
+      object-fit: scale-down;
+      z-index: 1001;
+      position: absolute;
     }
+  }
+
+  .step-in {
+    bottom: 80px;
+    top: initial;
+    color: white;
+    background: rgba(0, 0, 0, 1);
+    transform: translateX(-50%);
+    left: 50%;
+    display: inline-block;
+    text-align: center;
+    position: fixed;
+    padding: 10px;
+    width: 60px;
+    z-index: 10000;
+  }
 }
-</style>
+</style>

+ 1 - 0
src/components/RightMenu.vue

@@ -97,6 +97,7 @@ const changeScene = (item) => {
         span.sub {
             font-size: 9px;
             line-height: 0.8;
+            text-align: center;
         }
     }
 }