Krpano 二維全景圖項目開發記錄

Krpano是一款全景開發插件,廢話就很少說了,這篇文章用於記錄Krpano後臺集成開發,即將該插件應用到後臺系統中,上傳全景圖片後,可自動生成全景,同時能夠在場景編輯器中自定義路線、語音等,簡化了全景開發的複雜性。javascript

官方網站css

  • https://krpano.com

參考案例html

  • http://www.krpano.tech/

 

Krpano 二維全景圖項目開發記錄html5

全景圖嵌入式開發java

服務器端數據處理c++

全景圖場景編輯器git

全景圖數據文件生成github

全景圖數據文件回顯-涉及添加多個全景(*重要)web

 

Tour代碼模塊ajax

動態統一代碼模板(tour.xml.jsp)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<krpano version="1.19" title="Virtual Tour">
  <include url="%SWFPATH%/skin/vtourskin.xml?v=1.3" />
  <action name="startup" autorun="onstart">
  	if(startscene === null OR !scene[get(startscene)], copy(startscene,scene[0].name); );
  	loadscene(get(startscene), null, MERGE);
  	playsound(bgsnd, '', 0);
  	if(startactions !== null, startactions() );
  	js('onready');
  </action>
  
  <c:forEach items="${param.tourUrlIds}" var="UUID">
	  <scene name="${UUID}" title="${UUID}" onstart="" thumburl="panos/${UUID}/thumb.jpg" lat="" lng="" heading="">
			<view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" fovmin="5" fovmax="120" vlookatmin="-90" vlookatmax="90" limitview="lookat"/>
			<preview url="panos/${UUID}/preview.jpg" />
			<image>
				<cube url="panos/${UUID}/pano_%s.jpg" />
			</image>
	  </scene>
  </c:forEach>
  
</krpano>

Java代碼模塊

全景圖Tour.xml文件代碼生成及保存

全景圖Tour.xml文件代碼回顯二次生成保存

全景圖多圖選擇

/**
 * Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.thinkgem.jeesite.modules.hnly.web;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.junit.runners.Parameterized.Parameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.thinkgem.jeesite.common.config.Global;
import com.thinkgem.jeesite.common.mapper.JsonMapper;
import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.utils.FileUtils;
import com.thinkgem.jeesite.common.utils.IdGen;
import com.thinkgem.jeesite.common.utils.KrpanoUtils;
import com.thinkgem.jeesite.common.utils.StringUtils;
import com.thinkgem.jeesite.common.web.BaseController;
import com.thinkgem.jeesite.modules.hnly.entity.KrpanoHotspots;
import com.thinkgem.jeesite.modules.hnly.entity.KrpanoView;
import com.thinkgem.jeesite.modules.hnly.entity.Panoramic;
import com.thinkgem.jeesite.modules.hnly.entity.PanoramicMaterialPic;
import com.thinkgem.jeesite.modules.hnly.entity.PanoramicPicHotspots;
import com.thinkgem.jeesite.modules.hnly.entity.PanoramicPicMusic;
import com.thinkgem.jeesite.modules.hnly.entity.PanoramicPicView;
import com.thinkgem.jeesite.modules.hnly.service.PanoramicMaterialPicService;
import com.thinkgem.jeesite.modules.hnly.service.PanoramicPicHotspotsService;
import com.thinkgem.jeesite.modules.hnly.service.PanoramicPicMusicService;
import com.thinkgem.jeesite.modules.hnly.service.PanoramicPicViewService;
import com.thinkgem.jeesite.modules.hnly.service.PanoramicService;

/**
 * 全景圖管理Controller
 * @author WenC
 * @version 2017-08-15
 */
@Controller
@RequestMapping(value = "${adminPath}/hnly/panoramic")
public class PanoramicController extends BaseController {

	@Autowired
	private PanoramicService panoramicService;
	@Autowired
	private PanoramicMaterialPicService panoramicMaterialPicService;
	@Autowired
	private PanoramicPicViewService panoramicPicViewService;
	@Autowired
	private PanoramicPicHotspotsService panoramicPicHotspotsService;
	@Autowired
	private PanoramicPicMusicService panoramicPicMusicService;
	
	Map<String, String> iMap = new HashMap<String, String>();
	
	@ModelAttribute
	public Panoramic get(@RequestParam(required=false) String id) {
		Panoramic entity = null;
		if (StringUtils.isNotBlank(id)){
			entity = panoramicService.get(id);
		}
		if (entity == null){
			entity = new Panoramic();
		}
		return entity;
	}
	
	@RequiresPermissions("hnly:panoramic:view")
	@RequestMapping(value = {"list", ""})
	public String list(Panoramic panoramic, HttpServletRequest request, HttpServletResponse response, Model model) {
		Page<Panoramic> page = panoramicService.findPage(new Page<Panoramic>(request, response), panoramic); 
		model.addAttribute("page", page);
		return "modules/hnly/panoramicList";
	}

	@RequiresPermissions("hnly:panoramic:view")
	@RequestMapping(value = "form")
	public String form(Panoramic panoramic, Model model) {
		model.addAttribute("panoramic", panoramic);
		return "modules/hnly/panoramicForm";
	}

	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "save")
	public String save(Panoramic panoramic, Model model, @RequestParam("imagesUrl") MultipartFile file, HttpServletRequest request, RedirectAttributes redirectAttributes) {
		if (!beanValidator(model, panoramic)){
			return form(panoramic, model);
		}
		if(!file.isEmpty()){
			String uuid = IdGen.uuidAtoZ();
			String path = request.getSession().getServletContext().getRealPath("krpano/panos");  
	        String fileName = file.getOriginalFilename();
	        String uuidFileName = uuid + fileName.substring(fileName.lastIndexOf("."));
	        File dir = new File(path,uuidFileName);          
	        if(!dir.exists()){  
	            dir.mkdirs();  
	        }  
	        //MultipartFile自帶的解析方法  
	        try {
				file.transferTo(dir);
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String allPath = request.getContextPath() + "/krpano/panos/" + uuidFileName;
	        panoramic.setUrl(allPath);
		}
		panoramicService.save(panoramic);
		addMessage(redirectAttributes, "保存全景圖成功");
		return "redirect:"+Global.getAdminPath()+"/hnly/panoramic/?repage";
	}
	
	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "delete")
	public String delete(Panoramic panoramic, RedirectAttributes redirectAttributes) {
		panoramicService.delete(panoramic);
		addMessage(redirectAttributes, "刪除全景圖成功");
		return "redirect:"+Global.getAdminPath()+"/hnly/panoramic/?repage";
	}
	
	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "vtourGenerate")
	public String vtourGenerate(Panoramic panoramic, RedirectAttributes redirectAttributes){
		String tempThumbUrl = KrpanoUtils.krpanoVtourMultires(KrpanoUtils.VNP, panoramic.getUrl());
		panoramic.setThumbUrl(tempThumbUrl);
		panoramic.setTourUrl(KrpanoUtils.getTourUrl(panoramic.getUrl()));
		panoramicService.save(panoramic);
		addMessage(redirectAttributes, "生成全景圖成功");
		return "redirect:"+Global.getAdminPath()+"/hnly/panoramic/?repage";
	}
	
	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "multiSelect")
	public String multiSelect(Panoramic panoramic, HttpServletRequest request, HttpServletResponse response, Model model) {
//		System.out.println(panoramic.getPanoramicMaterialPicIdList());
		model.addAttribute("panoramic", panoramic);
		model.addAttribute("AllPanoramicMaterialPic", panoramicMaterialPicService.findList(null));
		return "modules/hnly/panoramicMultiSelect";
	}
	
	/**
	 * 全景圖更新
	 * @param panoramic
	 * @param request
	 * @param response
	 * @param model
	 */
	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "multiSelectSave")
	public void multiSelectSave(Panoramic panoramic, HttpServletRequest request, HttpServletResponse response, Model model) {
		// 更新全景關聯要素圖片數據
		String[] cpmpil = request.getParameterValues("panoramicMaterialPicIdList");
//		System.out.println(cpmpil);
//		if(null != cpmpil){
//			for(String s : cpmpil){
//				System.out.println(s);
//			}
//		}
//		System.out.println(panoramic.getPanoramicMaterialPicIdList());
		if(null == cpmpil){ //若是爲NULL,證實只選擇了主場景,沒有選擇其餘場景聯動
			panoramic.setPanoramicMaterialPicList(null);
		}
		panoramicService.updatePanoramicPic(panoramic);
		panoramic = panoramicService.get(panoramic.getId());
		String tourUrls = panoramic.getTourUrl();
//		String panoramicMaterialPicIds = "";
		for(int i=0;i<panoramic.getPanoramicMaterialPicList().size();i++){
			PanoramicMaterialPic pmp = panoramic.getPanoramicMaterialPicList().get(i);
			tourUrls = tourUrls + "," + pmp.getTourUrl();
//			panoramicMaterialPicIds = panoramicMaterialPicIds + pmp.getId() + ",";
//			if((i+1)==panoramic.getPanoramicMaterialPicList().size()){
//				panoramicMaterialPicIds = panoramicMaterialPicIds.substring(0, panoramicMaterialPicIds.length()-1);
//			}
		}
		String[] tourUrlsTemp = tourUrls.split(","); //頁面選中的場景數組數據
		List<PanoramicPicView> panoramicPicViewList = panoramicPicViewService.findListByPanoramicId(panoramic.getId());
		// ===== 存在代碼修改數據,檢查有無新增數據,有則添加codeView代碼原始模塊
		if(null != panoramicPicViewList && panoramicPicViewList.size()>0){ 
			String[] tourUrlsExist = new String[panoramicPicViewList.size()];
			for(int i=0;i<panoramicPicViewList.size();i++){
				tourUrlsExist[i] = panoramicPicViewList.get(i).getTourUrl();
			}
			List<String> delList = compare(tourUrlsTemp,tourUrlsExist);  
	        for (String str : delList) {  
//	            System.out.println(str);
	        	iMap.clear();
	        	iMap.put("panoramicId", panoramic.getId());
	        	iMap.put("tourUrl", str);
	        	panoramicPicViewService.delByPanoramicIdAndTourUrl(iMap);
	        }
	        List<String> addList = compare(tourUrlsExist,tourUrlsTemp);  
	        for (String str : addList) {  
//	            System.out.println(str);
	        	PanoramicPicView panoramicPicView = new PanoramicPicView();
				panoramicPicView.setTourUrl(str);
				panoramicPicView.setPanoramic(panoramic);
				panoramicPicView.setCode("<view hlookat=\"0\" vlookat=\"0\" fovtype=\"MFOV\" fov=\"90\" fovmin=\"5\" fovmax=\"120\" vlookatmin=\"-90\" vlookatmax=\"90\" limitview=\"auto\"/>\r\n");
				panoramicPicViewService.save(panoramicPicView);
	        }
		} else {
			for(String str : tourUrlsTemp){
				PanoramicPicView panoramicPicView = new PanoramicPicView();
				panoramicPicView.setTourUrl(str);
				panoramicPicView.setPanoramic(panoramic);
				panoramicPicView.setCode("<view hlookat=\"0\" vlookat=\"0\" fovtype=\"MFOV\" fov=\"90\" fovmin=\"5\" fovmax=\"120\" vlookatmin=\"-90\" vlookatmax=\"90\" limitview=\"auto\"/>\r\n");
				panoramicPicViewService.save(panoramicPicView);
			}
		}
		// ===== 存在代碼修改數據,檢查有無新增數據,新增長場景中去除原有場景則去除codeHotspots代碼模塊,在此不執行熱點原始代碼模塊,由於是一對多的關係
		List<PanoramicPicHotspots> panoramicPicHotspotsList = panoramicPicHotspotsService.findListByPanoramicId(panoramic.getId());
		if(null != panoramicPicHotspotsList && panoramicPicHotspotsList.size()>0){
			String[] tourUrlsExist = new String[panoramicPicHotspotsList.size()];
			for(int i=0;i<panoramicPicHotspotsList.size();i++){
				tourUrlsExist[i] = panoramicPicHotspotsList.get(i).getTourUrl();
			}
			List<String> delList = compare(tourUrlsTemp,tourUrlsExist); 
			for (String str : delList) {  
	            System.out.println(str);
				iMap.clear();
				iMap.put("panoramicId", panoramic.getId());
				iMap.put("tourUrl", str);
	        	panoramicPicHotspotsService.delByPanoramicIdAndTourUrl(iMap);
	        }
		}
		// ===== 獲取語音數據回顯
		List<PanoramicPicMusic> panoramicPicMusicList = panoramicPicMusicService.findListByPanoramicId(panoramic.getId());
		// ===== 配置文件回顯操做,從新生成配置文件
		if(null != panoramic && "1".equals(panoramic.getTourFlag())){
			panoramicPicViewList = panoramicPicViewService.findListByPanoramicId(panoramic.getId());
			StringBuffer sb = new StringBuffer();
			sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n");
			sb.append("<krpano version=\"1.19\" title=\"Virtual Tour\">\r\n");
			sb.append("<include url=\"%SWFPATH%/skin/vtourskin.xml?v=1.3\" />\r\n");
//			sb.append("<skin_settings maps=\"false\" maps_type=\"google\" maps_bing_api_key=\"\" maps_google_api_key=\"\" maps_zoombuttons=\"false\" gyro=\"true\" webvr=\"true\" webvr_gyro_keeplookingdirection=\"false\" webvr_prev_next_hotspots=\"true\" littleplanetintro=\"true\" 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\"/>");
			
			sb.append("<action name=\"startup\" autorun=\"onstart\">\r\n");
			sb.append("if(startscene === null OR !scene[get(startscene)], copy(startscene,scene[0].name); );loadscene(get(startscene), null, MERGE);playsound(bgsnd, '', 0);if(startactions !== null, startactions() );js('onready');\r\n");
			sb.append("</action>\r\n");
			for(int i=0;i<panoramicPicViewList.size();i++){
				PanoramicPicView panoramicPicView = panoramicPicViewList.get(i);
				String sceneName = panoramicPicView.getTourUrl();
				String codeView = panoramicPicView.getCode();
				sb.append("<scene name=\"" + sceneName + "\" title=\"" + sceneName + "\" onstart=\"\" thumburl=\"panos/" + sceneName + "/thumb.jpg\" ");
				for(int j=0;j<panoramicPicMusicList.size();j++){
					PanoramicPicMusic panoramicPicMusic = panoramicPicMusicList.get(j);
					if(sceneName.equals(panoramicPicMusic.getTourUrl())){
						sb.append(panoramicPicMusic.getCode() +  " ");
						break;
					}
				}
				sb.append("lat=\"\" lng=\"\" heading=\"\">\r\n");
				sb.append(codeView);
				sb.append("<preview url=\"panos/" + sceneName + "/preview.jpg\" />\r\n");
				sb.append("<image>\r\n");
				sb.append("<cube url=\"panos/" + sceneName + "/pano_%s.jpg\" />\r\n");
				sb.append("</image>\r\n");
				iMap.clear();
				iMap.put("panoramicId", panoramic.getId());
				iMap.put("tourUrl", sceneName);
				panoramicPicHotspotsList = panoramicPicHotspotsService.findListByPanoramicIdAndTourUrl(iMap);
				for(int j=0;j<panoramicPicHotspotsList.size();j++){
					PanoramicPicHotspots hotspots = panoramicPicHotspotsList.get(j);
					sb.append(hotspots.getCode());
					System.out.println(hotspots.getCode());
				}
				sb.append("</scene>\r\n");
			}
//			sb.append("<action name=\"add_all_the_time_tooltip_for_VR\">\r\n");
//			sb.append("txtadd(tooltipname, 'vrtooltip_', get(name));addhotspot(get(tooltipname)); set(hotspot[get(tooltipname)].type,text);copy(hotspot[get(tooltipname)].edge,hotspot[get(name)].edge);copy(hotspot[get(tooltipname)].distorted,hotspot[get(name)].distorted);copy(hotspot[get(tooltipname)].ath,hotspot[get(name)].ath);copy(hotspot[get(tooltipname)].atv,hotspot[get(name)].atv);set(hotspot[get(tooltipname)].oy,-50);set(hotspot[get(tooltipname)].ox,0);set(hotspot[get(tooltipname)].vcenter,false);set(hotspot[get(tooltipname)].padding,10);set(hotspot[get(tooltipname)].bg,true);set(hotspot[get(tooltipname)].bgcolor,0x000000);set(hotspot[get(tooltipname)].bgroundedge,5);set(hotspot[get(tooltipname)].bgalpha,0.65);set(hotspot[get(tooltipname)].bgborder,0);set(hotspot[get(tooltipname)].bgshadow,'0 0 0 0x000000 0');set(hotspot[get(tooltipname)].css,'text-align:left; color:#FFFFFF; font-family:MicrosoftYahei; font-size:24px;');if(device.mobile,set(hotspot[get(tooltipname)].css,'text-align:center; color:#FFFFFF; font-family:MicrosoftYahei; font-weight:bold; font-size:24px;'););set(hotspot[get(tooltipname)].txtshadow,'0 0 0 0x000000 0');if(text == '' OR text === null,copy(hotspot[get(tooltipname)].html,scene[get(linkedscene)].title),copy(hotspot[get(tooltipname)].html,text);); set(hotspot[get(tooltipname)].enabled,false); if(lp_running == false,set(hotspot[get(tooltipname)].visible,true); , 	if(!webvr.isenabled,if(lp_running == true,set(hotspot[get(tooltipname)].visible,false); set(hotspot[get(tooltipname)].mark2,true););););if(hotspot[get(name)].normal == false, set(hotspot[get(tooltipname)].normal,false);set(hotspot[get(tooltipname)].onloaded,if(webvr.isenabled,set(visible,false);,	if(lp_running == false OR lp_running == null OR lp_running === null,  set(visible,true);););););\r\n");
//			sb.append("</action>\r\n");
			sb.append("</krpano>\r\n");
			String path = request.getSession().getServletContext().getRealPath("krpano");
			String pathAll = path + "\\tour" +  panoramic.getTourUrl() + ".xml.jsp";
			FileUtils.createFile(pathAll);
			File f = new File(pathAll);
			try {  
			    FileOutputStream fos = new FileOutputStream(pathAll);  
			    //設置bom頭
			    fos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});  
			    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");  
			    BufferedWriter bw = new BufferedWriter(osw);  
			    bw.close();  
			} catch (IOException e) {  
			    System.out.println(e.toString());  
			}
			try {
				// 第四個屬性必需要設置true,對存在的文件執行追加操做,不然上面設置的bom頭會被覆蓋掉
				FileUtils.writeStringToFile(f, sb.toString(), "UTF-8", true);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		try {
			response.sendRedirect(request.getContextPath() + "/krpano/tour_editor_custom.jsp" 
					+ "?panoramicId=" + panoramic.getId() 
					+ "&tourUrl=" + panoramic.getTourUrl() 
					+ "&tourFlag=" + panoramic.getTourFlag()
//					+ "&panoramicMaterialPicIds=" + panoramicMaterialPicIds
					+ "&tourUrlIds=" + tourUrls);
			System.out.println(request.getContextPath() + "/krpano/tour_editor_custom.jsp" 
					+ "?panoramicId=" + panoramic.getId() 
					+ "&tourUrl=" + panoramic.getTourUrl() 
					+ "&tourFlag=" + panoramic.getTourFlag()
//					+ "&panoramicMaterialPicIds=" + panoramicMaterialPicIds
					+ "&tourUrlIds=" + tourUrls);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 全景圖保存
	 * @param panoramic
	 * @param request
	 * @param response
	 * @param data
	 * @throws IOException
	 */
	@RequiresPermissions("hnly:panoramic:edit")
	@RequestMapping(value = "vtourSave")
	public void vtourSave(Panoramic panoramic, HttpServletRequest request, HttpServletResponse response, @RequestBody String data) throws IOException{
//		data = URLDecoder.decode(URLDecoder.decode( data, "UTF-8"), "UTF-8");
		System.out.println(data);
		System.out.println(request.getParameter("panoramicId"));
		String panoramicId = request.getParameter("panoramicId");
		panoramic = panoramicService.get(panoramicId);
		System.out.println(request.getParameter("tourUrlIds"));
		String tourUrlIds = request.getParameter("tourUrlIds");
		String[] tourUrlIdsData = tourUrlIds.split(",");
//		System.out.println(request.getParameter("panoramicMaterialPicIds"));
//		String panoramicMaterialPicIds = request.getParameter("panoramicMaterialPicIds");
//		String[] panoramicMaterialPicIdsData = panoramicMaterialPicIds.split(",");
		
//		JSONObject obj = new JSONObject(data.substring(1, data.length()-1));
//		System.out.println(obj.getString("index"));
		JsonMapper ji = JsonMapper.getInstance();
		List<KrpanoView> krpanoViewList = (List<KrpanoView>)ji.fromJson(data, ji.createCollectionType(ArrayList.class, KrpanoView.class));
//		for(KrpanoView kv : krpanoViewList){
//			System.out.println(kv.getName());
//		}
//		KrpanoView kv = (KrpanoView) JsonMapper.fromJsonString(data.substring(1, data.length()-1), KrpanoView.class);
//		System.out.println(kv.getName() + kv.getInitH() + kv.getInitV());
		
		StringBuffer sb = new StringBuffer();
		String viewCode = "";
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n");
		sb.append("<krpano version=\"1.19\" title=\"Virtual Tour\">\r\n");
		sb.append("<include url=\"%SWFPATH%/skin/vtourskin.xml?v=1.3\" />\r\n");
		//sb.append("<skin_settings maps=\"false\" maps_type=\"google\" maps_bing_api_key=\"\" maps_google_api_key=\"\" maps_zoombuttons=\"false\" gyro=\"true\" webvr=\"true\" webvr_gyro_keeplookingdirection=\"false\" webvr_prev_next_hotspots=\"true\" littleplanetintro=\"true\" 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\"/>");
		
		sb.append("<action name=\"startup\" autorun=\"onstart\">\r\n");
		sb.append("if(startscene === null OR !scene[get(startscene)], copy(startscene,scene[0].name); );loadscene(get(startscene), null, MERGE);playsound(bgsnd, '', 0);if(startactions !== null, startactions() );js('onready');\r\n");
		sb.append("</action>\r\n");
		for(int i=0;i<tourUrlIdsData.length;i++){
			String sceneName = tourUrlIdsData[i];
			sb.append("<scene name=\"" + sceneName + "\" title=\"" + sceneName + "\" onstart=\"\" thumburl=\"panos/" + sceneName + "/thumb.jpg\" ");
			for(int j=0;j<krpanoViewList.size();j++){
				KrpanoView kv = krpanoViewList.get(j);
				if(kv.getName().equals(sceneName) && null != kv.getBgmusic()){
					String codeMusic = "bgmusic=\"" + kv.getBgmusic() + "\" ";
					sb.append(codeMusic);
					iMap.clear();
					iMap.put("panoramicId", panoramic.getId());
					iMap.put("tourUrl", sceneName);
					PanoramicPicMusic panoramicPicMusic = panoramicPicMusicService.findByPanoramicIdAndTourUrl(iMap);
					if(null == panoramicPicMusic){
						panoramicPicMusic = new PanoramicPicMusic();
						panoramicPicMusic.setPanoramic(panoramic);
						panoramicPicMusic.setTourUrl(sceneName);
					}
					panoramicPicMusic.setCode(codeMusic);
					panoramicPicMusicService.save(panoramicPicMusic);
					break;
				}
			}
			sb.append("lat=\"\" lng=\"\" heading=\"\">\r\n");
			for(int j=0;j<krpanoViewList.size();j++){
				KrpanoView kv = krpanoViewList.get(j);
//				System.out.println(kv.getName());
				
				if(kv.getName().equals(sceneName)){
					if(null != kv.getInitH() && null != kv.getInitV() && null != kv.getFov()){
						viewCode = "<view hlookat=\"" + kv.getInitH() + "\" vlookat=\"" + kv.getInitV() + "\" fovtype=\"MFOV\" fov=\"" + kv.getFov() + "\" fovmin=\"5\" fovmax=\"120\" vlookatmin=\"-90\" vlookatmax=\"90\" limitview=\"auto\"/>\r\n";
						iMap.clear();
						iMap.put("panoramicId", panoramic.getId());
						iMap.put("tourUrl", sceneName);
						PanoramicPicView panoramicPicView = panoramicPicViewService.findByPanoramicIdAndTourUrl(iMap);
						panoramicPicView.setCode(viewCode);
						panoramicPicViewService.save(panoramicPicView);
					} else {
						viewCode = "<view hlookat=\"0\" vlookat=\"0\" fovtype=\"MFOV\" fov=\"90\" fovmin=\"5\" fovmax=\"120\" vlookatmin=\"-90\" vlookatmax=\"90\" limitview=\"auto\"/>\r\n";
					}
					sb.append(viewCode);
					break;
				}
				// 根據實際測試,場景中有多少個圖片會傳多少個參數,這個暫時隱藏,如出現意外狀況,再加上
//				if((j+1)==krpanoViewList.size()){
//					viewCode = "<view hlookat=\"0\" vlookat=\"0\" fovtype=\"MFOV\" fov=\"90\" fovmin=\"5\" fovmax=\"120\" vlookatmin=\"-90\" vlookatmax=\"90\" limitview=\"auto\"/>\r\n";
//					sb.append(viewCode);
//				}
			}
			
			sb.append("<preview url=\"panos/" + sceneName + "/preview.jpg\" />\r\n");
			sb.append("<image>\r\n");
			sb.append("<cube url=\"panos/" + sceneName + "/pano_%s.jpg\" />\r\n");
			sb.append("</image>\r\n");
			for(int j=0;j<krpanoViewList.size();j++){
				KrpanoView kv = krpanoViewList.get(j);
				if(kv.getName().equals(sceneName)){
					for(KrpanoHotspots hotspots : kv.getHotSpots()){
						if(hotspots.getName().indexOf("vrtooltip") != -1) continue;
						String codeHotspots = "<hotspot text=\"" + hotspots.getText() + "\" ath=\"" + hotspots.getAth() + "\" atv=\"" + hotspots.getAtv() + "\" linkedscene=\"" + hotspots.getLinkedscene() + "\" name=\"" + hotspots.getName() + "\" style=\"" + hotspots.getStyle() + "\" dive=\"" + hotspots.isDive() + "\" onloaded=\"add_all_the_time_tooltip_for_VR()\"/>\r\n";
						//sb.append(codeHotspots);
						iMap.clear();
						iMap.put("panoramicId", panoramic.getId());
						iMap.put("tourUrl", sceneName);
						iMap.put("name", hotspots.getName());
						System.out.println(hotspots.getName());
						PanoramicPicHotspots panoramicPicHotspots = panoramicPicHotspotsService.findByPanoramicIdAndTourUrlAndName(iMap);
						if(null == panoramicPicHotspots){
							panoramicPicHotspots = new PanoramicPicHotspots();
							panoramicPicHotspots.setPanoramic(panoramic);
							panoramicPicHotspots.setTourUrl(sceneName);
							panoramicPicHotspots.setName(hotspots.getName());
							panoramicPicHotspots.setLinkedscene(hotspots.getLinkedscene());
						}
						panoramicPicHotspots.setCode(codeHotspots);
						panoramicPicHotspotsService.save(panoramicPicHotspots);
					}
					iMap.clear();
					iMap.put("panoramicId", panoramic.getId());
					iMap.put("tourUrl", sceneName);
					List<PanoramicPicHotspots> panoramicPicHotspotsList = panoramicPicHotspotsService.findListByPanoramicIdAndTourUrl(iMap);
					for(int k=0;k<panoramicPicHotspotsList.size();k++){
						PanoramicPicHotspots hotspots = panoramicPicHotspotsList.get(k);
						sb.append(hotspots.getCode());
						System.out.println(hotspots.getCode());
					}
				}
			}
			sb.append("</scene>\r\n");
		}
		//sb.append("<action name=\"add_all_the_time_tooltip_for_VR\">\r\n");
		//sb.append("txtadd(tooltipname, 'vrtooltip_', get(name));addhotspot(get(tooltipname)); set(hotspot[get(tooltipname)].type,text);copy(hotspot[get(tooltipname)].edge,hotspot[get(name)].edge);copy(hotspot[get(tooltipname)].distorted,hotspot[get(name)].distorted);copy(hotspot[get(tooltipname)].ath,hotspot[get(name)].ath);copy(hotspot[get(tooltipname)].atv,hotspot[get(name)].atv);set(hotspot[get(tooltipname)].oy,-50);set(hotspot[get(tooltipname)].ox,0);set(hotspot[get(tooltipname)].vcenter,false);set(hotspot[get(tooltipname)].padding,10);set(hotspot[get(tooltipname)].bg,true);set(hotspot[get(tooltipname)].bgcolor,0x000000);set(hotspot[get(tooltipname)].bgroundedge,5);set(hotspot[get(tooltipname)].bgalpha,0.65);set(hotspot[get(tooltipname)].bgborder,0);set(hotspot[get(tooltipname)].bgshadow,'0 0 0 0x000000 0');set(hotspot[get(tooltipname)].css,'text-align:left; color:#FFFFFF; font-family:MicrosoftYahei; font-size:24px;');if(device.mobile,set(hotspot[get(tooltipname)].css,'text-align:center; color:#FFFFFF; font-family:MicrosoftYahei; font-weight:bold; font-size:24px;'););set(hotspot[get(tooltipname)].txtshadow,'0 0 0 0x000000 0');if(text == '' OR text === null,copy(hotspot[get(tooltipname)].html,scene[get(linkedscene)].title),copy(hotspot[get(tooltipname)].html,text);); set(hotspot[get(tooltipname)].enabled,false); if(lp_running == false,set(hotspot[get(tooltipname)].visible,true); , 	if(!webvr.isenabled,if(lp_running == true,set(hotspot[get(tooltipname)].visible,false); set(hotspot[get(tooltipname)].mark2,true););););if(hotspot[get(name)].normal == false, set(hotspot[get(tooltipname)].normal,false);set(hotspot[get(tooltipname)].onloaded,if(webvr.isenabled,set(visible,false);,	if(lp_running == false OR lp_running == null OR lp_running === null,  set(visible,true);););););\r\n");
		//sb.append("</action>\r\n");
		sb.append("</krpano>\r\n");
		
		String path = request.getSession().getServletContext().getRealPath("krpano");
		String pathAll = path + "\\tour" +  panoramic.getTourUrl() + ".xml.jsp";
		FileUtils.createFile(pathAll);
		File f = new File(pathAll);
//		if(!f.exists()){  
//            f.mkdirs();  
//        } 
		try {  
		    FileOutputStream fos = new FileOutputStream(pathAll);  
		    //設置bom頭
		    fos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});  
		    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");  
		    BufferedWriter bw = new BufferedWriter(osw);  
		    bw.close();  
		} catch (IOException e) {  
		    System.out.println(e.toString());  
		}
		// 第四個屬性必需要設置true,對存在的文件執行追加操做,不然上面設置的bom頭會被覆蓋掉
		FileUtils.writeStringToFile(f, sb.toString(), "UTF-8", true);
		
		panoramic = panoramicService.get(panoramicId);
		panoramic.setTourFlag("1");
		panoramicService.save(panoramic);
		
    	response.setContentType("text/html;charset=utf-8");
    	PrintWriter pw = response.getWriter();
    	String mess = "保存成功";
		pw.write(URLDecoder.decode(mess, "utf-8"));
		pw.flush();
		pw.close();
	}
	
	public static <T> List<T> compare(T[] t1, T[] t2) {    
	      List<T> list1 = Arrays.asList(t1);    
	      List<T> list2 = new ArrayList<T>();    
	      for (T t : t2) {    
	          if (!list1.contains(t)) {    
	              list2.add(t);    
	          }    
	      }    
	      return list2;    
	  }  
}

Krpano工具類-生成場景

package com.thinkgem.jeesite.common.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import javax.servlet.http.HttpServletResponse;

public class KrpanoUtils {

	public static final String VN = "vtour-normal";
	public static final String VM = "vtour-multires";
	public static final String VNP = "vtour-normal-picture";
	public static final String VMP = "vtour-multires-picture";
	
	public static synchronized String krpanoVtourMultires(String type, String fileUrl){
		// 生成全景圖thumb的圖片地址
		String tempFileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1,  fileUrl.lastIndexOf("."));
		String tempThumbUrl = fileUrl.substring(0, fileUrl.lastIndexOf("/") + 1) 
				+ tempFileName + "/thumb.jpg";
		// 建立全景圖
		String projectRealPath = RequestResponseContext.getRequest().getSession().getServletContext().getRealPath("").replaceAll("\\\\\\\\","\\\\");
		String command = projectRealPath
				+ "\\krpano\\krpanotools64.exe makepano -config=" 
				+ "templates\\" + type + ".config "
				+ projectRealPath + fileUrl.replaceAll("/", "\\\\");
//				+ projectRealPath.substring(0, projectRealPath.lastIndexOf("\\")) + fileUrl.replaceAll("/", "\\\\");
		System.out.println(command);
		Runtime runtime = Runtime.getRuntime();
		StringBuilder sb = new StringBuilder();
		BufferedReader bufferedReader = null;
		Process process = null;
		try {
			process = runtime.exec(command);
			try {
				BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
				bw.write("y\r\n");
				bw.flush();
				bw.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line = null;
				while ((line = bufferedReader.readLine()) != null) {
					sb.append(line + "\n");
//					if(line.contains("overwrite")){
//						System.out.println(line);
//					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					bufferedReader.close();
					process.destroy();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
//			System.out.println(sb.toString());
		return tempThumbUrl;
	}
	
	// 獲取全景地址編號
	public static String getTourUrl(String fileUrl){
		String tempFileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1,  fileUrl.lastIndexOf("."));
		return tempFileName;
	}

	public static void main(String[] args) {
		System.out.println();
//		KrpanoUtils.krpanoVtourMultires(null);
	}

}

全景編輯器

tour_editor_custom.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>

<!DOCTYPE html>
<html>
<head>
    <title>全景高級編輯DEMO</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <meta http-equiv="x-ua-compatible" content="IE=edge"/>
    <link rel="stylesheet" href="./style/krpano.editor.css">
    <style>
        @-ms-viewport {
            width: device-width;
        }

        @media only screen and (min-device-width: 800px) {
            html {
                overflow: hidden;
            }
        }

        html {
            height: 100%;
        }

        body {
            height: 100%;
            overflow: hidden;
            margin: 0;
            padding: 0;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 16px;
            color: #FFFFFF;
            background-color: #000000;
        }
        .sureBtn {
        	background-color: #00a3d8;
			border-bottom-color: #00a3d8;
			border-bottom-left-radius: 0px;
			border-bottom-right-radius: 0px;
			border-bottom-style: solid;
			border-bottom-width: 1px;
			border-image-outset: 0;
			border-image-repeat: stretch stretch;
			border-image-slice: 100%;
			border-image-source: none;
			border-image-width: 1;
			border-left-color: #00a3d8;
			border-left-style: solid;
			border-left-width: 1px;
			border-right-color: #00a3d8;
			border-right-style: solid;
			border-right-width: 1px;
			border-top-color: #00a3d8;
			border-top-left-radius: 0px;
			border-top-right-radius: 0px;
			border-top-style: solid;
			border-top-width: 1px;
			box-sizing: border-box;
			color: rgb(255, 255, 255);
			cursor: pointer;
			display: inline-block;
			font-family: "microsoft yahei",Arial,Helvetica,sans-serif;
			font-feature-settings: normal;
			font-kerning: auto;
			font-language-override: normal;
			font-size: 13px;
			font-size-adjust: none;
			font-stretch: normal;
			font-style: normal;
			font-variant: normal;
			font-variant-alternates: normal;
			font-variant-caps: normal;
			font-variant-east-asian: normal;
			font-variant-ligatures: normal;
			font-variant-numeric: normal;
			font-variant-position: normal;
			font-weight: 400;
			line-height: 20px;
			list-style-image: none;
			list-style-position: outside;
			list-style-type: none;
			margin-bottom: 0px;
			margin-left: 0px;
			margin-right: 0px;
			margin-top: 0px;
			padding-bottom: 5px;
			padding-left: 12px;
			padding-right: 12px;
			padding-top: 5px;
			text-align: center;
			text-shadow: rgba(0, 0, 0, 0.2) 0px -1px 0px;
			text-transform: none;
			transition-delay: 0s;
			transition-duration: 0.4s;
			transition-property: all;
			transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
			vertical-align: middle;
			white-space: nowrap;
			-moz-border-bottom-colors: none;
			-moz-border-left-colors: none;
			-moz-border-right-colors: none;
			-moz-border-top-colors: none;
			-moz-user-select: none;
        }
    </style>
</head>
<body>

<script src="tour.js"></script>

<div id="pano" style="width:100%;height:100%;">
    <noscript>
        <table style="width:100%;height:100%;">
            <tr style="vertical-align:middle;">
                <td>
                    <div style="text-align:center;">ERROR:<br/><br/>Javascript not activated<br/><br/></div>
                </td>
            </tr>
        </table>
    </noscript>
    <script>
    	//alert("${param.prefixUrl}");
    	//touFlag爲1,爲回顯編輯模式,調用對應生成的XML文件,不然使用默認的模板文件
        embedpano({
            swf: "tour.swf",
            xml: "tour${param.tourFlag eq '1' ? param.tourUrl : ''}.xml.jsp?tourUrlIds=${param.tourUrlIds}",
            target: "pano",
            html5: "auto",
            mobilescale: 1.0,
            passQueryParameters: true
        });
    </script>
</div>

<input type="hidden" name="panoramicId" id="panoramicId" value="${param.panoramicId}"/>
<!-- 
<input type="hidden" name="panoramicMaterialPicIds" id="panoramicMaterialPicIds" value="${param.panoramicMaterialPicIds}"/> -->
<input type="hidden" name="tourUrlIds" id="tourUrlIds" value="${param.tourUrlIds}"/>

<div class="frame" name="#viewFrame">
    <button onclick="setAsDefaultView()" class="btn btn-blue">設爲初始視角</button>
    <div class="frame-line frame-line-top"></div>
    <div class="frame-line frame-line-right"></div>
    <div class="frame-line frame-line-bottom"></div>
    <div class="frame-line frame-line-left"></div>
    <span class="angle angle-tl"><i class="angle-a"></i><i class="angle-b"></i></span>
    <span class="angle angle-tr"><i class="angle-a"></i><i class="angle-b"></i></span>
    <span class="angle angle-bl"><i class="angle-a"></i><i class="angle-b"></i></span>
    <span class="angle angle-br"><i class="angle-a"></i><i class="angle-b"></i></span>
</div>
<div class="overlay overlay-right">
    <div class="save-wrap">
        <button onclick="save()" id="isEdited" class="btn btn-blue">保存</button>
    </div>
    <div class="tool-panel">
        <ul class="tool-btn-lst">
            <li>
                <span class="btn J-tool-btn btn-blue" data-target="#viewFrame">視角</span>
                <div class="tool-main" style="display: block" name="#viewFrame">
                    <section class="tool-section">
                        <div style="margin: 5px;">
                            <label style="padding-right: 5px;vertical-align: middle;" for="autoSpin">自動旋轉</label>
                            <input type="checkbox" name="autoSpin" id="autoSpin" style="vertical-align: middle;"
                                   onclick="autoSpinClick()"/>
                        </div>
                        <div id="waitTimeInput" style="display: none;margin: 5px;">
                            <label style="padding-right: 5px;vertical-align: middle;" for="waitTime">等待時間</label>
                            <input type="text" class="wait-time-input" id="waitTime" onblur="autoSpinClick()"/>
                            <label style="padding-left: 5px">秒</label>
                        </div>
                        <div style="margin: 5px;">
                            <label>(默認應用於全部場景)</label>
                        </div>
                    </section>
                    <section class="tool-section">
                        <div style="margin: 5px;">
                            <label>初始fov
                                <input type="text" class="fov-input" id="initFov" onblur="updateFov()"/>
                            </label>
                        </div>
                        <section id="sample-pb">
                            <article>
                                <div class="number-pb">
                                    <div class="number-pb-shown" style="display: none">
                                        <div class="triangle triangle-up-left" style="float: left;"></div>
                                        <div class="triangle triangle-down"></div>
                                        <div class="triangle triangle-up-right" style="float: right;"></div>
                                    </div>
                                    <div class="number-pb-num" style="left: 70%;">
                                    </div>
                                </div>
                            </article>
                        </section>
                        <div style="margin: 5px;">
                            <label>最小fov
                                <input type="text" class="fov-input" id="initFovMin" onblur="updateFov()"/>
                            </label>
                        </div>
                        <div style="margin: 5px;">
                            <label>最大fov
                                <input type="text" class="fov-input" id="initFovMax" onblur="updateFov()"/>
                            </label>
                        </div>
                        <div style="margin: 5px;">
                            <input type="button" style="vertical-align: middle;" value="應用於全部場景" class="btn btn-blue"
                                   onclick="fovForAll()"/>
                        </div>
                    </section>
                </div>
            </li>
            <li>
                <span class="btn J-tool-btn" data-target="#toolHot">熱點</span>
                <div class="tool-main" name="#toolHot" id="hotToolButton">
                    <section class="tool-section">
                        <h3 style="margin-bottom: 5px;">熱點類型</h3>
                        <button class="btn btn-blue">場景切換</button>
                    </section>
                    <section class="tool-section">
                        <h3 style="margin-bottom: 5px;">熱點列表</h3>
                        <ul>
                            <div id="hotSpotList"></div>
                            <script id="tplHotSpotList" type="text/html">
                                {{each list as eachSpot}}
                                <div class="hot-spot-list" name="{{eachSpot.name}}Hover">
                                    <div class="hot-spot-img" style="background-image: url('{{eachSpot.url}}')"
                                         spot-style="{{eachSpot.style}}"></div>
                                    <div class="hot-spot-text">{{eachSpot.linkedscene}}</div>
                                    <div class="hot-spot-del" onclick="removeHotSpot('{{eachSpot.name}}')">-</div>
                                </div>
                                {{/each}}
                            </script>
                        </ul>
                        <button class="hot-spot-button" onclick="showAddHotSpot()">+</button>
                    </section>
                </div>
            </li>
            <li>
                <span class="btn J-tool-btn" data-target="#toolVoice">音樂</span>
                <div class="tool-main" name="#toolVoice" id="toolVoiceButton">
                    <section class="tool-section">
                        <h3 style="margin-bottom: 5px;">音樂類型</h3>
                        <button class="btn btn-blue">語音播報</button>
                        <button class="btn btn-blue">背景音樂</button>
                    </section>
                    <section class="tool-section">
                        <h3 style="margin-bottom: 5px;">音樂列表</h3>
                        <ul>
                            <div id="bgMusicList"></div>
                            <script id="tplBgMusicList" type="text/html">
                                {{each list as eachMusic}}
                                <div class="hot-spot-list" name="{{eachMusic.name}}Hover">   
                                    <div class="hot-spot-text">{{eachMusic.name}}</div>
                                    <div class="hot-spot-del" onclick="removeBgMusic('{{eachMusic.name}}')">-</div>
                                </div>
                                {{/each}}
                            </script>
                        </ul>
                        <button class="hot-spot-button" onclick="showAddVoice()">+</button>
                    </section>
                </div>
            </li>
        </ul>
    </div>
</div>
<div class="left-column">
    <div class="scene-select">
        <div class="blue-banner"></div>
        <div class="select_scene_text">
            <p class="p_title">場景選擇</p>
        </div>
        <div class="blue-banner"></div>
        <ul style="margin: 0;padding: 0;">
            <div id="sceneList"></div>
            <script id="tplSceneList" type="text/html">
                {{each list as scene}}
                <li key="{{scene.index}}" name="{{scene.name}}" class="li-scene">
                    <div class="thumbs-img-scene-list"
                         style='background-image: url("panos/{{scene.name}}/thumb.jpg")'></div>
                    <div class="li-scene-span" onclick="changeScene({{scene.index}})">{{scene.name}}</div>
                    <input type="hidden" value="{{scene.name}}" class="li-scene-input" onblur="doRename($(this))"/>
                    <input type="button" class="scene-li-button" onclick="rename($(this).prev())"/>
                    <div class="circle" onclick="selectWelcomeScene({{scene.index}})"></div>
                </li>
                {{/each}}
            </script>
        </ul>
    </div>
</div>
<div class="add-hot-pot" style="display: none" name="#toolHot">
    <div class="add-hot-banner">添加全景切換熱點<a class="div-close" onclick="hideAddHotSpot()">×</a></div>
    <div class="progress-banner">
        <div class="progress-title progress-title-on" id="selectStyleTitle"><span style="line-height: 30px">選擇樣式</span>
        </div>
        <div class="progress-title" id="goToSceneTitle"><span style="line-height: 30px">選擇目標場景</span></div>
        <div class="progress-title" id="writeTitleTitle"><span style="line-height: 30px">填寫title</span></div>
    </div>
    <div>
        <div class="dive-text">俯衝效果:</div>
        <div class="my-open-out">
            <div class="my-open-in my-open-in-open"></div>
        </div>
    </div>
    <div id="selectStyle" class="add-hot-content">
        <div class="add-hot-bottom-div">
            <div class="hot-style"
                 style="background-image: url('./skin/vtourskin_hotspot.png')"
                 name="skin_hotspotstyle"></div>
        </div>
        <div class="add-hot-button" onclick="nextToSelectTargetScene()">下一步</div>
    </div>
    <div id="goToScene" class="add-hot-content" style="display: none">
        <div class="add-hot-bottom-div">
            <div id="targetScene"></div>
            <script id="tplTargetScene" type="text/html">
                {{each list as each}}
                <div class="select-scene-div" name="{{each.name}}">
                    {{each.name}}
                    <div class="thumbs-img" style='background-image: url("panos/{{each.name}}/thumb.jpg")'></div>
                </div>
                {{/each}}
            </script>
        </div>
        <div class="add-hot-button" onclick="nextToWriteTitle()">下一步</div>
    </div>
    <div id="writeTitle" class="add-hot-content write-title" style="display: none">
        <div class="add-hot-bottom-div">
            <p style="padding: 50px;"><label for="addHotTitle">請出入熱點上方的文字title(可不填):</label></p>
            <input type="text" id="addHotTitle"/>
        </div>
        <div class="add-hot-button" onclick="addHotSpot()">完成</div>
    </div>
</div>

<div class="add-voice" style="display: none" name="#toolVoice">
	<div class="add-hot-banner">添加背景語音/音樂<a class="div-close" onclick="hideAddVoice()">×</a></div>
	<div id="writeTitle" class="add-hot-content write-title">
        <div class="add-hot-bottom-div" id="add-voice-frame">
            <p style="padding: 20px;"><label for="addHotTitle">請選擇一段語音/音樂插入到場景中:</label> <button class="sureBtn" onclick="addVoice()">肯定選擇</button></p>
        </div>
    </div>
</div>

<script src="./script/jQuery-2.1.4.min.js"></script>
<script src="./script/krpano.editor.js"></script>
<script src="./script/template.min.js"></script>
</body>
</html>

krpano.editor.css

html, body, div, span, applet, input, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, menu, nav, output, ruby, section, summary, time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    vertical-align: baseline;
}

article, aside, details, figcaption, figure, footer, header, menu, nav, section {
    display: block;
}

body {
    line-height: 1;
}

ol, ul {
    list-style: none;
}

blockquote, q {
    quotes: none;
}

blockquote:before,
blockquote:after {
    content: none;
}

q:before,
q:after {
    content: "";
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

button {
    padding: 0;
    margin: 0;
    background-color: #fff;
    border: none;
    outline: 0;
}

body {
    font-family: 'PingFang SC', 'Helvetica Neue', 'Helvetica', 'STHeitiSC-Light', 'Arial', 'Microsoft Yahei', sans-serif;
    font-size: 14px;
    line-height: 1.5;
}

a {
    text-decoration: none;
}

.btn {
    cursor: pointer;
    display: inline-block;
    padding: 8px 20px;
    background-color: rgba(0, 0, 0, .7);
    color: #fff;
    border-radius: 4px;
    font-size: 14px;
}

.btn-blue {
    background-color: #2185D0;
}

.scene-name {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    background-color: rgba(0, 0, 0, .6);
    color: #fff;
    text-align: right;
    height: 40px;
    line-height: 40px;
    padding-right: 15px;
}

.frame-line {
    position: absolute;
    background-color: #eee;
}

.frame-line-top,
.frame-line-bottom {
    height: 1px;
    left: 30%;
    right: 30%;
}

.frame-line-top {
    top: 25%;
}

.frame-line-bottom {
    bottom: 25%;
}

.frame-line-left,
.frame-line-right {
    top: 25%;
    bottom: 25%;
    width: 1px;
}

.frame-line-left {
    left: 30%;
}

.frame-line-right {
    right: 30%;
}

.angle {
    width: 40px;
    height: 40px;
    position: absolute;
}

.angle i {
    position: absolute;
    background-color: #eee;
}

.angle-a {
    left: 0;
    width: 8px;
    top: 0;
    bottom: 0;
}

.angle-b {
    top: 0;
    left: 0;
    right: 0;
    height: 8px;
}

.angle-tl {
    left: 30%;
    top: 25%;
}

.angle-tr {
    right: 30%;
    top: 25%;
}

.angle-tr .angle-a {
    left: auto;
    right: 0;
}

.angle-bl {
    left: 30%;
    bottom: 25%;
}

.angle-bl .angle-b {
    bottom: 0;
    top: auto;
}

.angle-br {
    right: 30%;
    bottom: 25%;
}

.angle-br .angle-a {
    left: auto;
    right: 0;
}

.angle-br .angle-b {
    top: auto;
    bottom: 0;
}

.frame .btn {
    position: absolute;
    left: 50%;
    top: 30%;
    transform: translate(-50%, 0);
}

.overlay {
    position: absolute;
    right: 15px;
    top: 15px;
    z-index: 9999;
}

.save-wrap {
    margin-top: 40px;
    margin-bottom: 20px;
}

.tool-panel {
    position: relative;
}

.tool-btn-lst {
    float: right;
}

.tool-btn-lst > li {
    margin-bottom: 10px;
    position: relative;
}

.tool-main {
    moz-user-select: -moz-none;
    -moz-user-select: none;
    -o-user-select:none;
    -khtml-user-select:none;
    -webkit-user-select:none;
    -ms-user-select:none;
    user-select:none;
    display: none;
    position: absolute;
    right: 80px;
    top: 0;
    padding: 15px;
    background-color: rgba(0, 0, 0, .7);
    min-width: 200px;
    border-top: 3px solid #00a3d8;
}

.tool-section {
    border-bottom: 1px solid #2185D0;
    padding: 15px 0;
}

.tool-section:last-child {
    margin-bottom: 0;
    border-bottom: none;
    padding-bottom: 0;
}

.tool-section:first-child {
    padding-top: 0;
}

.tool-section h4 {
    color: #999;
}

.choose-lst {
    margin: 7px 0;
}

.choose-lst li {
    padding: 3px 0;
}

.choose-lst input {
    margin-right: 5px;
}

.left-column {
    position: absolute;
    top: 0;
    left: -250px;
    z-index: 9999;
    background-color: rgba(0, 0, 0, 0.3);
    width: 250px;
    height: 100%;
    -webkit-animation:hideLeft 0.8s infinite;
    -webkit-animation-iteration-count:1;
}

@-webkit-keyframes showLeft {
     0% {left: -250px;}
     100% {left: 0;}
}

@-webkit-keyframes hideLeft {
    0% {left: 0;}
    100% {left: -250px;}
}

.scene-select {
    margin-top: 20px;
    margin-left: 10px;
    margin-right: 10px;
    background-color: rgba(0, 0, 0, 0.5);
    padding-bottom: 1px;
    overflow: auto;
    max-height: 600px;
    overflow-x: hidden;
}

.blue-banner {
    background-color: #00a3d8;
    height: 3px;
}

.li-scene {
    list-style-type: none;
    height: 30px;
    border: 2px solid rgba(255, 255, 255, 0);
    margin: 10px;
    width: 200px;
}

.li-scene:hover {
    border-color: #FF9800;
}

.li-scene-hover {
    border-color: #FF9800;
}

.li-scene-span {
    cursor: pointer;
    height: 30px;
    font-size: 16px;
    line-height: 30px;
    float: left;
    width: 100px;
    overflow: hidden;
}

.li-scene-input {
    background-color: rgba(185, 185, 185, 0.5);
    height: 30px;
    width: 100px;
    font-size: 18px;
}

.scene-li-button {
    width: 30px;
    height: 30px;
    background: rgba(255, 255, 255, 0) url("../img/krpano.modify.png");
    border: 0;
    float: right;
    cursor: pointer;
}

.circle {
    width: 30px;
    height: 30px;
    float: right;
    background: #292827 url("../img/krpano.home.png");
    border-radius: 50%;
    text-align: center;
    line-height: 30px;
    cursor: pointer;
}

.select_scene_text {
    text-align: center;
    background-color: rgba(40, 40, 40, 0.7);
    height: 50px;
}

.p_title {
    margin-top: 0;
    font-size: 20px;
    line-height: 50px;
}

.add-hot-pot {
    position: absolute;
    z-index: 9999;
    background-color: rgba(0, 0, 0, 0.8);
    width: 700px;
    height: 440px;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}

.add-voice {
    position: absolute;
    z-index: 9999;
    background-color: rgba(0, 0, 0, 0.8);
    width: 700px;
    height: 440px;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}

.progress-banner {
    margin: 20px;
    background-color: rgba(150, 150, 150, 0.4);
    height: 30px;
}

.progress-title {
    float: left;
    text-align: center;
    width: 33.33%;
    height: 100%;
}

.progress-title-on {
    background-color: #00a3d8;
}

.add-hot-banner {
    font-size: 16px;
    background-color: rgba(150, 150, 150, 0.4);
    padding: 8px 8px 8px 15px;
    height: 20px;
    line-height: 20px;
}

.div-close {
    cursor: pointer;
    float: right;
    font-size: 30px;
}

.add-hot-content {
    margin: 10px 20px 20px 20px;
}

.add-hot-bottom-div {
    height: 250px;
}

.write-title {
    font-size: 18px;
    text-align: center;
}

#addHotTitle {
    color: white;
    width: 57%;
    background-color: rgba(150, 150, 150, 0.4);
}

.add-hot-button {
    cursor: pointer;
    background-color: #00a3d8;
    line-height: 30px;
    text-align: center;
    font-size: 18px;
    height: 30px;
}

.hot-style {
    background-color: rgba(255, 255, 255, 0);
    border: 2px solid rgba(255, 255, 255, 0);
    cursor: pointer;
    margin: 7px;
    width: 64px;
    height: 56px;
    background-size: cover;
    float: left;
}

.hot-spot-img {
    background-color: rgba(255, 255, 255, 0);
    width: 32px;
    height: 32px;
    background-size: cover;
    float: left;
}

.hot-style:hover {
    border: 2px solid orange;
}

.hot-style-on {
    border: 2px solid orange;
}

.select-scene-div {
    float: left;
    width: 80px;
    text-align: center;
    cursor: pointer;
    margin: 5px;
}

.select-scene-div:hover {
    margin: 3px;
    border: 2px solid orange;
}

.select-scene-div-on {
    margin: 3px;
    border: 2px solid orange;
}

.thumbs-img {
    height: 80px;
    background-size: 80px 80px;
    margin-top: 5px;
    margin-left: auto;
    margin-right: auto;
}

.thumbs-img-scene-list {
    width: 30px;
    height: 30px;
    background-size: 30px 30px;
    float: left;
    margin-right: 10px;
}

.hot-pot-select-span {
    position: absolute;
    left: 15px;
    top: 5px;
}

.wait-time-input {
    vertical-align: middle;
    width: 30px;
    background-color: rgba(255, 255, 255, 0.5);
    text-align: center
}

.fov-input {
    vertical-align: middle;
    width: 65px;
    background-color: rgba(255, 255, 255, 0.5);
    text-align: center;
    float: right;
    height: 21px;
}

.hot-spot-list {
    height: 32px;
    width: 200px;
    color: white;
    font-size: 18px;
    border: solid 2px rgba(0, 0, 0, 0);
    margin-top: 5px;
}

.hot-spot-text {
    width: 130px;
    height: 26px;
    float: left;
    text-align: center;
    padding: 3px;
}

.hot-spot-del {
    cursor: pointer;
    width: 32px;
    height: 32px;
    float: left;
    text-align: center;
    background-color: rgba(255, 255, 255, 0.1);
}

.hot-spot-button {
    cursor: pointer;
    background-color: rgba(255, 255, 255, 0.1);
    height: 32px;
    width: 202px;
    color: white;
    font-size: 18px;
    margin-top: 10px;
}

.hot-spot-list-hover {
    border: solid 2px orange;
}

.number-pb {
    position: relative;
    height: 3px;
    background-color: #ffffff;
    margin: 40px 0;
}

.number-pb .number-pb-shown {
    position: absolute;
    background: #00a3d8;
    left: 0;
    height: 3px;
}

.number-pb .number-pb-num {
    position: absolute;
    background-color: #00a3d8;
    left: 0;
    padding: 0 5px;
}

.triangle-up-left {
    border-bottom: 20px solid #00a3d8;
    margin-top: 3px;
    margin-left: -10px;
}

.triangle-up-right {
    border-bottom: 20px solid #00a3d8;
    margin-top: 3px;
    margin-right: -10px;
}

.triangle-down {
    border-top: 20px solid #00a3d8;
    margin-top: -20px;
    float: none;
}

.triangle {
    width: 0;
    height: 0;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
}

.my-open-out {
    margin-left: 90px;
    width: 40px;
    height: 20px;
    border-radius: 10px;
    position: relative;
    background: #00a3d8;
}

.my-open-in {
    width: 18px;
    height: 18px;
    border-radius: 9px;
    position: absolute;
    background: white;
    box-shadow: 0 2px 4px rgba(0,0,0,0.4);
    top: 1px;
}

.my-open-in-open {
    right: 1px;
}

.my-open-in-close {
    left: 1px;
}

.dive-text {
    line-height: 20px;
    float: left;
    margin-left: 20px;
}

jQuery-2.1.4.min.js

(略),自行下載。

template.min.js

/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(/<!--[\w\W]*?-->/g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(B){throw B.temp="function anonymous($data,$filename) {"+z+"}",B}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a,b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","&":"&#38;"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;d>c;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(j){return j.filename=h||"anonymous",j.name="Syntax Error",p(j)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;e.openTag="{{",e.closeTag="}}";var z=function(a,b){var c=b.split(":"),d=c.shift(),e=c.join(":")||"";return e&&(e=", "+e),"$helpers."+d+"("+a+e+")"};e.parser=function(a){a=a.replace(/^\s/,"");var b=a.split(" "),c=b.shift(),e=b.join(" ");switch(c){case"if":a="if("+e+"){";break;case"else":b="if"===b.shift()?" if("+b.join(" ")+")":"",a="}else"+b+"{";break;case"/if":a="}";break;case"each":var f=b[0]||"$data",g=b[1]||"as",h=b[2]||"$value",i=b[3]||"$index",j=h+","+i;"as"!==g&&(f="[]"),a="$each("+f+",function("+j+"){";break;case"/each":a="});";break;case"echo":a="print("+e+");";break;case"print":case"include":a=c+"("+b.join(",")+");";break;default:if(/^\s*\|\s*[\w\$]/.test(e)){var k=!0;0===a.indexOf("#")&&(a=a.substr(1),k=!1);for(var l=0,m=a.split("|"),n=m.length,o=m[l++];n>l;l++)o=z(o,m[l]);a=(k?"=":"=#")+o}else a=d.helpers[c]?"=#"+c+"("+b.join(",")+");":"="+a}return a},"function"==typeof define?define(function(){return d}):"undefined"!=typeof exports?module.exports=d:this.template=d}();

krpano.editor.js

var krpano = document.getElementById("krpanoSWFObject");
var sceneList = [];
var toAddHotSpot = {};
var currentSceneIndex = 0;
var movingSpot = {};
//視角拖動模塊變量
var pbX = 0;
var moveIntervalId;
var canDownMove = false;
var canLeftMove = false;
var canRightMove = false;
//設置爲不動態顯示,在頁面中直接顯示就行了 已經設置left: 0 !important;到頁面中
var canShowLeft = true;

$(function () {

    //右側功能選擇
    $(".J-tool-btn").click(function () {
        $(".J-tool-btn").each(function () {
            $(this).removeClass("btn-blue");
            $("[name=" + $(this).attr("data-target") + "]").hide();
        });
        $(this).addClass("btn-blue");
        $("[name=" + $(this).attr("data-target") + "]").show();
        window.clearInterval(moveIntervalId);
        $(".add-hot-pot").hide();
        $(".add-voice").hide();
    });

    //視角拖動條
    $(".triangle-down").mouseup(function () {
        canDownMove = false;
    }).mouseout(function () {
        canDownMove = false;
    });
    $(".triangle-up-left").mouseup(function () {
        canLeftMove = false;
    }).mouseout(function () {
        canLeftMove = false;
    });
    $(".triangle-up-right").mouseup(function () {
        canRightMove = false;
    }).mouseout(function () {
        canRightMove = false;
    });

    //添加熱點模塊
    $(".hot-style").click(function () {
        toAddHotSpot.style = $(this).attr("name");
        $(".hot-style").removeClass("hot-style-on");
        $(this).addClass("hot-style-on");
    });
    $(this).mousemove(function () {
        if (canShowLeft) {
            if (krpano.get("mouse.x") <= 300) {
                $(".left-column").css("-webkit-animation", "showLeft 0.8s infinite").css("-webkit-animation-iteration-count", "1")
                    .css("left", "0");
            } else {
                $(".left-column").css("-webkit-animation", "hideLeft 0.8s infinite").css("-webkit-animation-iteration-count", "1")
                    .css("left", "-250px");
            }
        }
    });

    $(".my-open-out").click(function () {
        if (toAddHotSpot.dive) {
            toAddHotSpot.dive = false;
            $(this).css("background", "rgba(255,255,255,0.4)");
            $(".my-open-in").removeClass("my-open-in-open").addClass("my-open-in-close");
        } else {
            toAddHotSpot.dive = true;
            $(this).css("background", "#00a3d8");
            $(".my-open-in").removeClass("my-open-in-close").addClass("my-open-in-open");
        }
    });
});

//noinspection JSUnusedGlobalSymbols
function onready() {
    //隱藏下方自帶控制條
    krpano.set("layer[skin_control_bar].visible", false);
    krpano.set("layer[skin_splitter_bottom].visible", false);
    krpano.set("layer[skin_scroll_window].visible", false);
    //初始化場景選擇列表
    var sceneListHTML;
    var dataSceneList = {list: []};      
    
    krpano.get("scene").getArray().forEach(function (scene) {
        dataSceneList.list.push({name: scene.name, index: scene.index, bgmusic: scene.bgmusic});
    });
    sceneListHTML = template('tplSceneList', dataSceneList);
    document.getElementById('sceneList').innerHTML = sceneListHTML;
           
    //初始化選中以及首場景
    $("li[name=" + krpano.get("startscene") + "] .circle").css("background-color", "#FF9800");
    $("li[name=" + krpano.get("xml.scene") + "]").addClass("li-scene-hover");
    currentSceneIndex = krpano.get("scene").getItem(krpano.get("xml.scene")).index;
    
    //熱點列表模塊
    var hotSpotHTML;
    var dataHotSpotList = {list: []};
    //覆蓋原熱點選中事件,添加熱點點擊移動事件
    krpano.get("hotspot").getArray().forEach(function (oldHotSpot) {
    	
        if (oldHotSpot.name !== 'vr_cursor' && oldHotSpot.name !== 'webvr_prev_scene'
            && oldHotSpot.name !== 'webvr_next_scene') {
            dataHotSpotList.list.push(oldHotSpot);
            hotSpotInitEvent(oldHotSpot.name);
        }
    });
    hotSpotHTML = template('tplHotSpotList', dataHotSpotList);
    document.getElementById('hotSpotList').innerHTML = hotSpotHTML;    

  //背景音樂列表模塊
    var bgMusicHTML;
    var dataBgMusicList = {list: []};
    var bgMusicUrl=krpano.get("scene").getItem(currentSceneIndex).bgmusic;
    if(typeof(bgMusicUrl) != "undefined")
    {
        var bgmusicArr=bgMusicUrl.split("/");
        var bgMusicName=bgmusicArr[bgmusicArr.length-1].substring(0,bgmusicArr[bgmusicArr.length-1].length-4);
    	dataBgMusicList.list.push({name: bgMusicName});
    }   
    bgMusicHTML = template('tplBgMusicList', dataBgMusicList);
    document.getElementById('bgMusicList').innerHTML = bgMusicHTML;  
    
    //右側數值初始化
    $("#waitTime").val(krpano.get("autorotate.waittime"));
    if (krpano.get("autorotate.enabled")) {
        $("#autoSpin").prop("checked", true);
        $("#waitTimeInput").show();
    } else {
        $("#autoSpin").prop("checked", false);
        $("#waitTimeInput").hide();
    }
    $("#initFov").val(krpano.get("view.fov").toFixed(0));
    $("#initFovMax").val(krpano.get("view.fovmax").toFixed(0));
    $("#initFovMin").val(krpano.get("view.fovmin").toFixed(0));
    updatePbLine();
    initPbLineEvent();

    //初始化提交數據
    if (!sceneList.length) {
        krpano.get("scene").getArray().forEach(function (scene) {
            var sceneObj = {};
            sceneObj.index = scene.index;
            sceneObj.name = scene.name;
            sceneObj.bgmusic = scene.bgmusic;
            if (scene.name == krpano.get("startscene")) {
                sceneObj.welcomeFlag = true;
            }
            sceneList.push(sceneObj);
        });
    }
}

//場景切換,重命名模塊
function changeScene(index) {
    krpano.call("loadscene(" + krpano.get("scene").getItem(index).name + ")");
    //當前存儲對象展現
    var currentScene = sceneList[index];        
    
    if (currentScene.initH) krpano.set("view.hlookat", currentScene.initH);
    if (currentScene.initV) krpano.set("view.vlookat", currentScene.initV);
    if (currentScene.fov) krpano.set("view.fov", currentScene.fov);
    if (currentScene.fovmax) krpano.set("view.fovmax", currentScene.fovmax);
    if (currentScene.fovmin) krpano.set("view.fovmin", currentScene.fovmin);
    if (currentScene.autorotate) {
        krpano.set("autorotate.enabled", currentScene.autorotate.enabled);
        krpano.set("autorotate.waittime", currentScene.autorotate.waitTime);
    }
    if (currentScene.hotSpots) {
        krpano.get("hotspot").getArray().forEach(function (everySpot) {
            if (everySpot.name !== "vr_cursor" && everySpot.name !== 'webvr_prev_scene'
                && everySpot.name !== 'webvr_next_scene') {
                krpano.call("removehotspot(" + everySpot.name + ")");
            }
        });
        currentScene.hotSpots.forEach(function (everySpot) {
            krpano.call("addhotspot(" + everySpot.name + ");");
            krpano.set("hotspot[" + everySpot.name + "].ath", everySpot.ath);
            krpano.set("hotspot[" + everySpot.name + "].atv", everySpot.atv);
            krpano.set("hotspot[" + everySpot.name + "].text", everySpot.text);
            krpano.set("hotspot[" + everySpot.name + "].linkedscene", everySpot.linkedscene);
            krpano.set("hotspot[" + everySpot.name + "].dive", everySpot.dive);
            krpano.get("hotspot[" + everySpot.name + "]").loadstyle(everySpot.style);
        });
    }
    $('.li-scene-hover').removeClass('li-scene-hover');
    $("li[name=" + krpano.get("xml.scene") + "]").addClass("li-scene-hover");
    $(".circle").css("background-color", "#292827");
    sceneList.forEach(function (scene) {
        if (scene.welcomeFlag) {
            $(".circle:eq(" + scene.index + ")").css("background-color", "#FF9800");
            krpano.set("startscene", scene.name);
        }
    });
    onready();
}

function rename(prevButton) {
    prevButton.prev().hide();
    prevButton.attr("type", "text");
    var focusValue = prevButton.val();
    prevButton.val("");
    prevButton.focus();
    prevButton.val(focusValue);
}

function doRename(thisInput) {
    var nameIndex = thisInput.parent().attr('key');
    var newName = thisInput.val();
    var oldName = krpano.get("scene").getItem(nameIndex).name;
    var doFlag = true;
    //判斷名字是否重複
    sceneList.forEach(function (eachScene) {
        if (eachScene.index !== nameIndex) {
            if (eachScene.name === newName) {
                doFlag = false;
                return false;
            }
        }
    });
    if (doFlag) {
        krpano.get("scene").renameItem(oldName, newName);
        if (currentSceneIndex === nameIndex) {
            krpano.set("xml.scene", newName);
        }
        if (oldName === krpano.get("startscene")) {
            krpano.set("startscene", newName);
        }
        sceneList[nameIndex].name = newName;
        //修改熱點指向場景名字
        sceneList.forEach(function (eachScene) {
            if (eachScene.index !== nameIndex && eachScene.hotSpots) {
                eachScene.hotSpots.forEach(function (eachSpot) {
                    if (eachSpot.linkedscene === oldName) {
                        eachSpot.linkedscene = newName;
                        eachSpot.text = newName;
                        krpano.set("hotspot[" + eachSpot.name + "].text", newName);
                        krpano.set("hotspot[" + eachSpot.name + "].linkedscene", newName);
                    }
                });
            }
        });
        $(".hot-spot-text").each(function () {
            if ($(this).text() == oldName) {
                $(this).text(newName);
            }
        });
        $("#isEdited").text('保存*');
        thisInput.prev().text(newName);
    } else {
        thisInput.val(oldName);
        alert("名字重複");
    }
    thisInput.prev().show();
    thisInput.attr("type", "hidden");
}

function selectWelcomeScene(index) {
    $(".circle").css("background-color", "#292827");
    $(".circle:eq(" + index + ")").css("background-color", "#FF9800");
    sceneList.forEach(function (scene) {
        scene.welcomeFlag = false;
    });
    sceneList[index].welcomeFlag = true;
    $("#isEdited").text('保存*');
}

//視角修改模塊
function setAsDefaultView() {
    sceneList[currentSceneIndex].initH = krpano.get("view.hlookat");
    sceneList[currentSceneIndex].initV = krpano.get("view.vlookat");
    sceneList[currentSceneIndex].fov = krpano.get("view.fov");
    $("#initFov").val(krpano.get("view.fov").toFixed(0));
    updatePbLine();
    $("#isEdited").text('保存*');
}

function autoSpinClick() {
    var isChecked = $("#autoSpin").is(":checked");
    if (isChecked) {
        $("#waitTimeInput").show();
    } else {
        $("#waitTimeInput").hide();
    }
    krpano.set("autorotate.enabled", isChecked);
    krpano.set("autorotate.waittime", $("#waitTime").val());
    krpano.get("scene").getArray().forEach(function (scene) {
        sceneList[scene.index].autorotate = {enabled: $("#autoSpin").is(":checked"), waitTime: $("#waitTime").val()};
    });
    $("#isEdited").text('保存*');
}

function updateFov() {
    var fov = $("#initFov").val();
    var fovMax = $("#initFovMax").val();
    var fovMin = $("#initFovMin").val();
    if (fov == "" || Number(fov) > 180 || Number(fov) < 0) {
        $("#initFov").val(krpano.get("view.fov").toFixed(0));
        return
    }
    if (fovMax == "" || Number(fovMax) > 180 || Number(fovMax) < 0) {
        $("#initFovMax").val(krpano.get("view.fovmax").toFixed(0));
        return
    }
    if (fovMin == "" || Number(fovMin) > 180 || Number(fovMin) < 0) {
        $("#initFovMin").val(krpano.get("view.fovmin").toFixed(0));
        return
    }
    krpano.set("view.fov", fov);
    krpano.set("view.fovmax", fovMax);
    krpano.set("view.fovmin", fovMin);
    sceneList[currentSceneIndex].fov = fov;
    sceneList[currentSceneIndex].fovmax = fovMax;
    sceneList[currentSceneIndex].fovmin = fovMin;
    updatePbLine();
    $("#isEdited").text('保存*');
}

function fovForAll() {
    sceneList.forEach(function (eachScene) {
        eachScene.fov = $("#initFov").val();
        eachScene.fovmax = $("#initFovMax").val();
        eachScene.fovmin = $("#initFovMin").val();
    });
    $("#isEdited").text('保存*');
    alert("操做成功");
}

function updatePbLine() {
    //視角條
    var startPx = Number(krpano.get("view.fovmin")) / 0.9;
    var widthPx = Number(krpano.get("view.fovmax")) / 0.9 - startPx;
    var currPx = Number(krpano.get("view.fov")) / 0.9 - startPx - 10;
    $(".triangle-down").css("margin-left", currPx.toFixed(0) + "px");
    $(".number-pb-shown").css("left", startPx.toFixed(0) + "px").css("width", widthPx.toFixed(0) + "px").show();
}

function initPbLineEvent() {
    $(".triangle-down").unbind("mousedown").mousedown(function () {
        pbX = krpano.get("mouse.x");
        canDownMove = true;
    }).unbind("mousemove").mousemove(function () {
        if (canDownMove) {
            moveDownLine();
        }
    });
    $(".triangle-up-left").unbind("mousedown").mousedown(function () {
        pbX = krpano.get("mouse.x");
        canLeftMove = true;
    }).unbind("mousemove").mousemove(function () {
        if (canLeftMove) {
            moveLeftLine();
        }
    });
    $(".triangle-up-right").unbind("mousedown").mousedown(function () {
        pbX = krpano.get("mouse.x");
        canRightMove = true;
    }).unbind("mousemove").mousemove(function () {
        if (canRightMove) {
            moveRightLine();
        }
    });
}

function moveDownLine() {
    var startPx = Number(krpano.get("view.fovmin")) / 0.9;
    var widthPx = Number(krpano.get("view.fovmax")) / 0.9 - startPx;
    var leftPx = Number(krpano.get("view.fov")) / 0.9 - startPx - 10 + krpano.get("mouse.x") - pbX;
    if (leftPx + 10 < 0) {
        canDownMove = false;
        leftPx = -10;
    }
    if (leftPx + 10 > widthPx) {
        canDownMove = false;
        leftPx = widthPx - 10;
    }
    pbX = krpano.get("mouse.x");
    krpano.set("view.fov", (leftPx + 10 + startPx) * 0.9);
    $(".triangle-down").css("margin-left", leftPx.toFixed(0) + "px");
    $("#initFov").val(krpano.get("view.fov").toFixed(0));
    sceneList[currentSceneIndex].fov = krpano.get("view.fov");
    $("#isEdited").text('保存*');
}

function moveLeftLine() {
    var startPx = Number(krpano.get("view.fovmin")) / 0.9 + krpano.get("mouse.x") - pbX;
    var endPx = Number(krpano.get("view.fovmax")) / 0.9;
    if (startPx < 0) {
        startPx = 0;
        canLeftMove = false;
    }
    if (endPx - startPx < 20) {
        startPx = endPx - 20;
        canLeftMove = false;
    }
    if (krpano.get("view.fov") < krpano.get("view.fovmin")) {
        krpano.set("view.fov", krpano.get("view.fovmin"))
    }
    pbX = krpano.get("mouse.x");
    krpano.set("view.fovmin", startPx * 0.9);
    updatePbLine();
    $("#initFovMin").val(krpano.get("view.fovmin").toFixed(0));
    sceneList[currentSceneIndex].fovmin = krpano.get("view.fovmin");
    $("#isEdited").text('保存*');
}

function moveRightLine() {
    var startPx = Number(krpano.get("view.fovmin")) / 0.9;
    var endPx = Number(krpano.get("view.fovmax")) / 0.9 + krpano.get("mouse.x") - pbX;
    if (endPx > 200) {
        endPx = 200;
        canRightMove = false;
    }
    if (endPx - startPx < 20) {
        endPx = startPx + 20;
        canRightMove = false;
    }
    if (krpano.get("view.fov") > krpano.get("view.fovmax")) {
        krpano.set("view.fov", krpano.get("view.fovmax"))
    }
    pbX = krpano.get("mouse.x");
    krpano.set("view.fovmax", endPx * 0.9);
    updatePbLine();
    $("#initFovMax").val(krpano.get("view.fovmax").toFixed(0));
    sceneList[currentSceneIndex].fovmax = krpano.get("view.fovmax");
    $("#isEdited").text('保存*');
}

//提交表單修改模塊
function updateHotSpotData() {
    var hotSpotHTML;
    var dataHotSpotList = {list: []};
    //修改全局變量
    var hotSpotData = [];
    krpano.get("hotspot").getArray().forEach(function (everySpot) {
        if (everySpot.name !== "vr_cursor" && everySpot.name !== 'webvr_prev_scene'
            && everySpot.name !== 'webvr_next_scene' && everySpot.name.indexOf('vrtooltip') == -1) {
        	//這裏加判斷過濾掉vrtooltip熱點標籤
            dataHotSpotList.list.push(everySpot);
            var hotSpot = {};
            hotSpot.ath = everySpot.ath.toString();
            hotSpot.atv = everySpot.atv.toString();
            hotSpot.linkedscene = everySpot.linkedscene;
            hotSpot.name = everySpot.name;
            hotSpot.style = everySpot.style;
            hotSpot.text = everySpot.text;
            hotSpot.dive = everySpot.dive;
            hotSpotData.push(hotSpot);
        }
    });
    sceneList[currentSceneIndex].hotSpots = hotSpotData;
    hotSpotHTML = template('tplHotSpotList', dataHotSpotList);
    document.getElementById('hotSpotList').innerHTML = hotSpotHTML;
}

//數據保存並提交操做
function save() {
    if ($("#isEdited").text() === '保存') {
        return;
    }
    var postData = JSON.stringify(sceneList);
    var panoramicId = $("#panoramicId").val();
    var panoramicMaterialPicIds = $("#panoramicMaterialPicIds").val();
    var tourUrlIds = $("#tourUrlIds").val();
    var curWwwPath = window.document.location.href;
    var pathName = window.document.location.pathname;
    var pos = curWwwPath.indexOf(pathName);
    var localhostPaht = curWwwPath.substring(0, pos);
    var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
    var prefix = localhostPaht + projectName +  "/a";
    alert(postData);
    alert(panoramicId);
    alert(tourUrlIds);
    alert(prefix);
    $.ajax({
        type: 'POST',
        contentType: "application/json; charset=utf-8",
        url: prefix + "/hnly/panoramic/vtourSave?panoramicId=" + panoramicId + "&tourUrlIds=" + tourUrlIds,
        data: postData,
        success: function (data) {
            alert(data);
            if (data === "保存成功") {
                $("#isEdited").text('保存');
            }
        },
        error: function () {
            alert("系統錯誤");
        }
    });
}

//熱點移動模塊
function autoMove() {
    krpano.call("screentosphere(mouse.x, mouse.y, mouseath, mouseatv);");
    krpano.set("hotspot[" + movingSpot.name + "].ath", krpano.get("mouseath") + movingSpot.athDis);
    krpano.set("hotspot[" + movingSpot.name + "].atv", krpano.get("mouseatv") + movingSpot.atvDis);
    krpano.set("hotspot[vrtooltip_" + movingSpot.name + "].ath", krpano.get("mouseath") + movingSpot.athDis);
    krpano.set("hotspot[vrtooltip_" + movingSpot.name + "].atv", krpano.get("mouseatv") + movingSpot.atvDis);
}

//添加熱點模塊
function showAddHotSpot() {
    $(".hot-style").removeClass("hot-style-on");
    $(".hot-style").first().addClass("hot-style-on");
    toAddHotSpot.style = $(".hot-style").first().attr("name");
    toAddHotSpot.dive = true;
    $(".my-open-out").css("background", "#00a3d8");
    $(".my-open-in").removeClass("my-open-in-close").addClass("my-open-in-open");
    $("#hotToolButton").hide();
    $(".add-hot-pot").show();
    $("#selectStyle").show();
    $("#goToScene").hide();
    $("#writeTitle").hide();
    $("#selectStyleTitle").addClass("progress-title-on");
    $("#goToSceneTitle").removeClass("progress-title-on");
    $("#writeTitleTitle").removeClass("progress-title-on");
}

//隱藏添加熱點窗口
function hideAddHotSpot() {
    window.clearInterval(moveIntervalId);
    toAddHotSpot = {};
    $(".add-hot-pot").hide();
    $("span[data-target=#toolHot]").click();
}

//隱藏添加語音窗口
function hideAddVoice() {
	$("div").remove(".radio-voice");
    $("#add-voice").hide();
    $("span[data-target=#toolVoice]").click();
}

function nextToSelectTargetScene() {
    if (!toAddHotSpot.style) {
        alert("請選擇熱點樣式");
        return
    }

    window.clearInterval(moveIntervalId);

    // 目標場景列表
    var targetSceneHTML;
    var dataTargetScene = {list: []};
    krpano.get("scene").getArray().forEach(function (scene) {
        if (scene.name !== krpano.get('xml.scene')) {
            dataTargetScene.list.push({name: scene.name, index: scene.index + 1})
        }
    });
    targetSceneHTML = template('tplTargetScene', dataTargetScene);
    document.getElementById('targetScene').innerHTML = targetSceneHTML;

    $(".select-scene-div").removeClass("select-scene-div-on");
    $(".select-scene-div").first().addClass("select-scene-div-on");
    toAddHotSpot.linkedscene = $(".select-scene-div").first().attr("name");
    $(".select-scene-div").unbind("click").click(function () {
        toAddHotSpot.linkedscene = $(this).attr("name");
        $(".select-scene-div").removeClass("select-scene-div-on");
        $(this).addClass("select-scene-div-on");
    });

    $("#selectStyle").hide();
    $("#goToScene").show();
    $("#writeTitle").hide();
    $("#goToSceneTitle").addClass("progress-title-on");
    $("#selectStyleTitle").removeClass("progress-title-on");
    $("#writeTitleTitle").removeClass("progress-title-on");
}

function nextToWriteTitle() {
    if (!toAddHotSpot.linkedscene) {
        alert("請選擇目標場景");
        return;
    }

    $("#addHotTitle").val(toAddHotSpot.linkedscene);

    $("#selectStyle").hide();
    $("#goToScene").hide();
    $("#writeTitle").show();
    $("#writeTitleTitle").addClass("progress-title-on");
    $("#selectStyleTitle").removeClass("progress-title-on");
    $("#goToSceneTitle").removeClass("progress-title-on");
}

//添加語音/音樂模塊
function showAddVoice(){
	$(".add-voice").show();
	
	var postData = "";
	var curWwwPath = window.document.location.href;
    var pathName = window.document.location.pathname;
    var pos = curWwwPath.indexOf(pathName);
    var localhostPaht = curWwwPath.substring(0, pos);
    var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
    var prefix = localhostPaht + projectName +  "/a";
    $.ajax({
        type: 'POST',
        contentType: "application/json; charset=utf-8",
        url: prefix + "/hnly/panoramicMaterialMusic/getData",
        data: postData,
        success: function (data) {
        	var panoramicMaterialMusicLists = data.panoramicMaterialMusicList;
        	for(var i=0;i<panoramicMaterialMusicLists.length;i++){
        		//alert(JSON.stringify(panoramicMaterialMusicLists[i].id));
        		
        		$("<div style=\"float: left;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;\" class=\"radio-voice\">" 
        		//$("<div style=\"-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;\" class=\"radio-voice\">" 
        				//+ "<div style=\"position: relative;float: left;width: 25%;line-height: 40px;font-weight: 700;text-align: left;\">"
        				+ "<div style=\"position: relative;line-height: 40px;font-weight: 700;\">"
        				+ "<label for=" + JSON.stringify(panoramicMaterialMusicLists[i].id)
        				+ "> <input type=\"radio\" name=\"panoramicMaterialMusicId\" value=" 
        				+ JSON.stringify(panoramicMaterialMusicLists[i].url) 
        				+ " id=" 
        				+ JSON.stringify(panoramicMaterialMusicLists[i].name) + "/> "
        				+ panoramicMaterialMusicLists[i].name 
        				+ "</label> " 
        				+ "</div>"
        				+ "<div style=\"position: relative;\">"
        				//+ "<div style=\"position: relative;float: left;width: 75%;\">"
        				//+ "<audio controls=\"controls\" height=\"40\" width=\"100\">"
						//+ "<source src=" + panoramicMaterialMusicLists[i].url + " type=\"audio/wav\" />"
						//+ "<source src=\"song.ogg\" type=\"audio/ogg\" />"
						//+ "<embed height=\"40\" width=\"100\" src=" + panoramicMaterialMusicLists[i].url + " />"
						//+ "</audio>" 
						
						+ "</div>"
					+ "</div>"
        				).appendTo("#add-voice-frame");
        	}
        },
        error: function () {
            alert("系統錯誤");
        }
    });
    $("#isEdited").text('保存*');
}

//添加熱點到場景列表中,關閉熱點彈出窗口
function addHotSpot() {
    // 計算中間位置的球面座標
    krpano.set("halfHeight", krpano.get("stageheight") / 2);
    krpano.set("halfWidth", krpano.get("stagewidth") / 2);
    krpano.call("screentosphere(halfWidth,halfHeight,init_h,init_v);");
    var init_h = krpano.get("init_h");
    var init_v = krpano.get("init_v");   
    
    //添加熱點
    var newHotSpotName = "spot" + new Date().getTime();
    krpano.call("addhotspot(" + newHotSpotName + ");");
    krpano.get("hotspot[" + newHotSpotName + "]").loadstyle(toAddHotSpot.style);
    krpano.set("hotspot[" + newHotSpotName + "].ath", init_h);
    krpano.set("hotspot[" + newHotSpotName + "].atv", init_v);
    krpano.set("hotspot[" + newHotSpotName + "].text", $("#addHotTitle").val());
    krpano.set("hotspot[" + newHotSpotName + "].linkedscene", toAddHotSpot.linkedscene);
    krpano.set("hotspot[" + newHotSpotName + "].dive", toAddHotSpot.dive);
    krpano.set("hotspot[" + newHotSpotName + "].onloaded", "add_all_the_time_tooltip_for_VR();");
    hotSpotInitEvent(newHotSpotName);
    updateHotSpotData();
    $("#isEdited").text('保存*');
    hideAddHotSpot();
    $("span[data-target=#toolHot]").click();
}

//添加語音到場景列表中,關閉語音彈出窗口
function addVoice(){
	var musicName;
	var obj = document.getElementsByName("panoramicMaterialMusicId");
	for(i=0; i<obj.length;i++){
		if(obj[i].checked){
			musicName=obj[i].value;	
			updateVoice(obj[i].id);
			krpano.get("scene").getItem(currentSceneIndex).bgmusic= obj[i].id;
			sceneList[currentSceneIndex].bgmusic=obj[i].value;
		}
	}
	
	hideAddVoice();
}

function updateVoice(musicName){
	var bgMusicHTML;
	var dataBgMusicList = {list: []};	
	dataBgMusicList.list.push({name: musicName});	
    bgMusicHTML = template('tplBgMusicList', dataBgMusicList);
    document.getElementById('bgMusicList').innerHTML = bgMusicHTML;
}


//熱點選擇模塊
function selectHotSpot() {
    krpano.call("screentosphere(mouse.x, mouse.y, mouseath, mouseatv);");
    var nearHotSpot = {};
    krpano.get("hotspot").getArray().forEach(function (thisHotSpot) {
        var thisAthDis = krpano.get("hotspot[" + thisHotSpot.name + "]").ath - krpano.get("mouseath");
        var thisAtvDis = krpano.get("hotspot[" + thisHotSpot.name + "]").atv - krpano.get("mouseatv");
        var thisDis = Math.abs(thisAthDis) + Math.abs(thisAtvDis);
        if (!nearHotSpot.name) {
            nearHotSpot = {name: thisHotSpot.name, athDis: thisAthDis, atvDis: thisAtvDis, dis: thisDis};
        } else {
            if (thisDis < nearHotSpot.dis) {
                nearHotSpot = {name: thisHotSpot.name, athDis: thisAthDis, atvDis: thisAtvDis, dis: thisDis};
            }
        }
    });
    return nearHotSpot;
}

//熱點初始化事件
function hotSpotInitEvent(spotName) {
    krpano.get("hotspot[" + spotName + "]").ondown = function () {
        movingSpot = selectHotSpot();
        var intervalId = setInterval(autoMove, 1000.0 / 30.0);
        krpano.set("autoMoveIntervalId", intervalId);
        canShowLeft = false;
    };
    krpano.get("hotspot[" + spotName + "]").onup = function () {
        window.clearInterval(krpano.get("autoMoveIntervalId"));
        movingSpot = {};
        updateHotSpotData();
        canShowLeft = true;
        $("#isEdited").text('保存*');
    };
    krpano.get("hotspot[" + spotName + "]").onclick = null;
    krpano.get("hotspot[" + spotName + "]").onover = function () {
        if (movingSpot === {}) {
            var currentSpot = selectHotSpot();
            $("[name=" + currentSpot.name + "Hover]").addClass("hot-spot-list-hover");
        }
    };
    krpano.get("hotspot[" + spotName + "]").onout = function () {
        $(".hot-spot-list").removeClass("hot-spot-list-hover");
    };
}

//去除熱點
function removeHotSpot(name) {
    krpano.call("removehotspot(" + name + ")");
    updateHotSpotData();
    $("#isEdited").text('保存*');
}

//去除背景音樂
function removeBgMusic(name) {
	var bgMusicHTML;
	var dataBgMusicList = {list: []};	
    bgMusicHTML = template('tplBgMusicList', dataBgMusicList);
    document.getElementById('bgMusicList').innerHTML = bgMusicHTML;
    $("#isEdited").text('保存*');
    
    krpano.get("scene").getItem(currentSceneIndex).bgmusic= null;
	sceneList[currentSceneIndex].bgmusic=null;
}
相關文章
相關標籤/搜索