{"id":18405721,"url":"https://github.com/ningbonb/nodekrpano","last_synced_at":"2025-04-06T06:13:56.745Z","repository":{"id":38215059,"uuid":"89544977","full_name":"ningbonb/nodeKrpano","owner":"ningbonb","description":"Krpano 全景笔记","archived":false,"fork":false,"pushed_at":"2020-09-25T01:41:58.000Z","size":31,"stargazers_count":379,"open_issues_count":0,"forks_count":111,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-30T05:08:30.060Z","etag":null,"topics":["javascript","krpano","krpano-xml","xml"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ningbonb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-27T02:04:55.000Z","updated_at":"2025-03-26T03:38:13.000Z","dependencies_parsed_at":"2022-09-04T14:52:58.605Z","dependency_job_id":null,"html_url":"https://github.com/ningbonb/nodeKrpano","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ningbonb%2FnodeKrpano","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ningbonb%2FnodeKrpano/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ningbonb%2FnodeKrpano/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ningbonb%2FnodeKrpano/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ningbonb","download_url":"https://codeload.github.com/ningbonb/nodeKrpano/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247441062,"owners_count":20939239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","krpano","krpano-xml","xml"],"created_at":"2024-11-06T03:04:15.390Z","updated_at":"2025-04-06T06:13:56.719Z","avatar_url":"https://github.com/ningbonb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## 前言\nKrpano 可以方便快速的构建全景场景或全景视频，[官网地址](https://krpano.com) 。\n\n### 预览地址\n[http://go.163.com/2015/public/team/ningbo/krpano/comn01/][demo]\n\n### 版本说明\n本篇文章使用的版本为：`krpano 1.19-pr16 (build 2018-04-04)` ，操作系统为 ` Windows` 。\n\n## 目录\n\n* [Krpano 功能简介](#krpano-功能简介)\n* [vtour 文件夹简介](#vtour-文件夹简介)\n* [krpano XML 结构与简介](#krpano-xml-结构与简介)\n* [常用设置](#常用设置)\n\n## Krpano 功能简介\n官方软件安装之后，解压后的文件夹里主要有六种全景的模式，其中 `MAKE　PANO` 为单全景模式， `MAKE VTOUR` 为多个全景合集的 **虚拟漫游** 。\n\n### Krpano 功能简介目录\n* [MAKE PANO (NORMAL)](#make-pano-normal)\n* [MAKE PANO (MULTIRES)](#make-pano-multires)\n* [MAKE PANO (SINGLESWF)](#make-pano-singleswf)\n* [MAKE VTOUR (NORMAL)](#make-vtour-normal)\n* [MAKE VTOUR (MULTIRES)](#make-vtour-multires)\n* [Convert SPHERE to CUBE](#convert-sphere-to-cube)\n* [Convert CUBE to SPHERE](#convert-cube-to-sphere)\n* [Encrypt XML](#encrypt-xml)\n\t\n### MAKE PANO (NORMAL)\n\n#### 简介\n\n1. 该模式为基础 360 单全景模式；\n2. 该模式生成的全景为 **单分辨率** 全景；\n\n#### 配置路径\n\n- 默认模版/皮肤配置文件: `skin/defaultskin.xml`\n\n----------\n\n### MAKE PANO (MULTIRES)\n\n#### 简介\n\n1. 该模式为 360 单全景模式；\n2. 多分辨率，可快速动态加载。\n\n#### 配置路径\n\n默认模版/皮肤配置文件: `skin/defaultskin.xml`\n\n----------\n\n### MAKE PANO (FLAT)\n\n#### 简介\n\n1. 该模式为平铺模式；\n2. 仅支持 `Flash` 。\n\n#### 配置路径\n\n- 默认模版/皮肤配置文件: `skin/defaultskin.xml`\n\n----------\n\n### MAKE VTOUR (NORMAL)\n\n#### 简介\n\n1. 生成普通（单分辨率）全景并将它们整合到一个虚拟漫游中；\n2. 全部全景图将会一次性载入，默认方块最大边长为 2048 像素（可以在配置文件中修改）；\n3. 包含一个包括导航按钮、可滚动缩略图的默认皮肤。\n\n#### 配置路径\n\n- 默认模版/皮肤配置文件: `skin/vtourskin.xml`\n\n----------\n\n### MAKE VTOUR (MULTIRES)\n\n#### 简介\n\n1. 生成多分辨率全景并将它们整合到一个虚拟漫游中；\n2. 动态载入，没有尺寸/分辨率限制；\n3. 包含一个包括导航按钮、可滚动缩略图的默认皮肤。\n\n#### 配置路径\n\n- 默认模版/皮肤配置文件: `skin/vtourskin.xml`\n\n----------\n\n### Convert SPHERE to CUBE\n\n#### 简介\n\n1. 将球面图像转换为立方体图。\n\n----------\n\n\n### Convert CUBE to SPHERE\n\n#### 简介\n\n1. 将六张立方体图像转换成一张球面全景图。\n\n----------\n\n### Encrypt XML\n\n#### 简介\n\n1. 将 `xml` 文件拖放进 `droplet` 进行加密；\n2. 加密过程中 `xml` 文件会自动被压缩；\n\n----------\n\n\n### 自定义 droplet\n\n如果内置 `droplet` 不能满足需求或者需要对一些参数进行自定义。只要复制并重命名一个配置文件与皮肤配置文件，然后复制并重命名一个 `droplet `，修改里面的配置路径即可。\n\n----------\n\n\n## vtour 文件夹简介\n\n###  vtour 文件夹说明目录\n* [vtour 文件夹结构](#vtour-文件夹结构)\n* [vtour 运作机制](#vtour-运作机制)\n\n### vtour 文件夹结构\n\n```\nvtour/\n| -- panos/             # 存放全景切片图片的文件夹\n| -- skin/              # 存放皮肤相关文件\n| -- plugins/           # 用来存放插件\n| -- tour.swf           # krpano flash viewer\n| -- tour.js            # krpano HTML5 viewer\n| -- tour.xml           # 生成全景的相关配置\n| -- tour.html          # 用来浏览全景的页面，需要本地服务环境\n| -- tour_editor.html   # 添加热点（hotspot）与初始化视角的设置\n```\n\n### vtour 运作机制\n\n```html\n\u003cdiv id=\"pano\"\u003e\u003c/div\u003e\n\u003cscript src=\"tour.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\nembedpano({\n    swf: \"tour.swf\", // 有则表示加载 flash 引擎，如果设置 html5:only 则不需要该值\n    xml: \"tour.xml\", // 启动时的配置文件\n    target: \"pano\", // 要渲染到的目标容器 ID\n    html5: \"only\", // 如果有需要用到 flash ，可设置为 auto\n    //id: \"krpanoSWFObject\", // 默认的 krpano 对象，每一个 viewer 对应唯一 id ，与 JS 交互时要用到\n    mobilescale: 1.0, //移动设备缩放，1 表示不缩放，默认 0.5\n    passQueryParameters: false //是否接受 URL 传参，例如：tour.html?html5=only\u0026startscene=scene2\n});\n\u003c/script\u003e\n```\n\n## krpano XML 结构与简介\n\n```xml\n\u003ckrpano\u003e\n    \u003cinclude\u003e\n    \u003cpreview\u003e\n    \u003cimage\u003e\n    \u003cview\u003e\n    \u003carea\u003e\n    \u003cdisplay\u003e\n    \u003ccontrol\u003e\n    \u003ccursors\u003e\n    \u003cautorotate\u003e\n    \u003cplugin\u003e\n    \u003clayer\u003e\n    \u003chotspot\u003e\n    \u003cstyle\u003e\n    \u003cevents\u003e\n    \u003caction\u003e\n    \u003ccontextmenu\u003e\n    \u003cnetwork\u003e\n    \u003cmemory\u003e\n    \u003csecurity\u003e\n    \u003ctextstyle\u003e\n    \u003clensflareset\u003e\n    \u003clensflare\u003e\n    \u003cdata\u003e\n    \u003cscene\u003e\n\u003c/krpano\u003e\n```\n\n### krpano XML结构目录\n\n* [Krpano 内置元素说明](#krpano-内置元素说明)\n\n### Krpano 内置元素说明\n\n#### 01.krpano\n\n`krpano` 元素是 `krpano xml` 文件的根元素。任何一个 `krpano xml` 文件内的其它元素都要被 `krpano` 元素所嵌套。\n\n#### 02.include\n\n`include` 元素用来引入其它 `xml` 文件的内容。例如我们常要用到的 `vtourskin.xml` 就是使用 `include` 嵌入到主 `xml` 中。\n\n#### 03.preview\n\n预览图设置，也就是全景图完全载入之前的模糊图像。因为体积较小，因此载入速度较快，会在全景图之前先载入，避免黑屏。\n\n#### 04.image\n\n`image` 元素用来设置全景图，包括全景图类型，渐进分辨率切片显示等。\n\n#### 05.view\n\n`view` 元素控制全景的视野，例如起始视角、视角限制与缩放等等。当要设置限制视角或设定特定的初始视角时，需要自行设定或使用插件获取代码。\n\n#### 06.area\n\n`area` 元素控制全景图在浏览器窗口中显示区域大小。\n\n#### 07.display\n\n控制全景图的显示品质。\n\n#### 08.control\n\n设置鼠标、键盘以及触摸设备对全景浏览的控制方式。\n\n#### 09.cursors\n\n设置鼠标光标样式。\n\n#### 10.autorotate\n\n控制自动旋转。\n\n#### 11.plugin\n\n用来调用插件、插入图片或生成容器。\n\n#### 12.layer\n\n与 `plugin` 作用相同，只是名称不同。\n\n#### 13.hotspot\n\n热点，可在 3D 空间中插入图片，使之随着 3D 空间一同运动，可制作很多特效。\n\n#### 14.style\n\n可以保存其它元素的属性子集。\n\n#### 15.events\n\n可调用各类型事件，例如全景载入的不同阶段以及鼠标触发的不同行为等。\n\n#### 16.action\n\n自定义动态代码。\n\n#### 17.contextmenu\n\n定义右键菜单的内容。\n\n#### 18.network\n\n控制图像的下载、缓存与解码。\n\n#### 19.menory\n\n控制全景图在设备中的存储。\n\n#### 20.security\n\n`Flashplayer` 和 `HTML5` 相关的安全/跨域设置。\n\n#### 21.lensflareset\n\n镜头眩光的设置（目前只能在 `flash` 下使用）。\n\n#### 22.lensflare\n\n生成镜头眩光（目前只能在 `flash` 下使用）。\n\n#### 23.data\n\n可放置任意的数据。\n\n#### 24.scene\n\n可放置任意 `krpano` 元素。每个 `scene` 元素只有在被 `loadscene` 时才会被载入到浏览器进行解析。\n\n## 常用设置\n\n### 常用设置目录\n\n* [小行星开场](#小行星开场)\n* [加载动画](#加载动画)\n* [修改右键菜单](#修改右键菜单)\n* [自定义热点](#自定义热点)\n* [隐藏皮肤](#隐藏皮肤)\n* [添加动态热点](#动态热点)\n* [动态热点添加始终显示的文字](#动态热点添加始终显示的文字)\n* [热点和或图层在鼠标点击或鼠标悬停时进入动态模式](#热点和或图层在鼠标点击或鼠标悬停时进入动态模式)\n* [拖拽热点](#拖拽热点)\n* [添加简单的全景视频](#添加简单的全景视频)\n* [添加雨雪特效](#添加雨雪特效)\n* [自动旋转](#自动旋转)\n* [无按钮控制的自动旋转](#无按钮控制的自动旋转)\n* [按钮控制的自动旋转](#按钮控制的自动旋转)\n* [添加陀螺仪](#添加陀螺仪)\n* [场景过渡效果](#场景过渡效果)\n* [隐藏显示热点](#隐藏显示热点)\n* [获取全景视频进度](#获取全景视频进度)\n* [用 js 控制全景](#用-js-控制场景跳转)\n\n### 小行星开场\n开启小行星，先找到 `tour.xml` ，然后搜索 `littleplanetintro` 将其值设置为 `true` 即可。\n\n```xml\n\u003cskin_settings\n    ...\n    littleplanetintro=\"true\"\n    ...\n/\u003e\n```\n\n### 加载动画\n在官方的案例文件夹中找到 `loading-progress` 这个文件夹，将需要的文件内容复制到项目中的 `skin` 文件夹，然后在 `tour.xml` 文件中引入该文件即可，这样重新打开就可以看到有动态的进度条了。\n\n```xml\n\u003cinclude url=\"skin/loadingbar.xml\" /\u003e\n```\n\n### 修改右键菜单\n找到引入的皮肤文件，默认在 `vtourskin.xml` ，然后修改下面这些地方即可自定义右键菜单，但像版权、全屏菜单即使删除也会存在。\n\n```xml\n\u003ccontextmenu\u003e\n    \u003citem name=\"fv\" caption=\"鱼眼视图\" onclick=\"skin_view_fisheye();\" showif=\"view.vlookatrange == 180\" devices=\"flash|webgl\" separator=\"true\" /\u003e\n\u003c/contextmenu\u003e\n```\n  \n#### contextmenu 元素\n\n- `caption` 右键菜单显示的文字；\n- `onclick` 控制点击后执行的动作，动作由 `action` 定义；\n- `showif` 显示条目的条件；\n- `devices` 控制在 `flash/webgl` 哪个模式中出现；\n- `separator` 显示分隔符来分隔菜单；\n\n### 自定义热点\n\n配置 `\u003chotspot\u003e` 中 `style` 的属性对应的元素（`skin`对应的文件夹）。\n\n```xml\n\u003chotspot name=\"spot1\" style=\"skin_hotspotstyle\" ath=\"93.531\" atv=\"-1.109\" linkedscene=\"scene_shuilifang\" /\u003e\n```\n\n```xml\n\u003c!-- skin_hotspotstyle - style for the hotspots --\u003e\n\t\u003cstyle name=\"skin_hotspotstyle\" url=\"vtourskin_hotspot.png\" scale=\"0.5\" edge=\"top\" distorted=\"true\"\n\t       tooltip=\"\"\n\t       linkedscene=\"\"\n\t       linkedscene_lookat=\"\"\n\t       onclick=\"skin_hotspotstyle_click();\"\n\t       onover=\"tween(scale,0.55);\"\n\t       onout=\"tween(scale,0.5);\"\n\t       onloaded=\"if(linkedscene AND skin_settings.tooltips_hotspots, copy(tooltip,scene[get(linkedscene)].title); loadstyle(skin_tooltips); );\"\n\t       /\u003e\n```\n\n### 隐藏皮肤\n\n```xml\n\u003caction name=\"startup\" autorun=\"onstart\"\u003e\n\t\u003c!--添加代码 隐藏皮肤 --\u003e\n\tset(events[skin_events].name, null);\n  \tfor(set(i,0), i LT layer.count, inc(i), \n\tcopy(layername, layer[get(i)].name);\n\tsubtxt(namestart, get(layername), 0, 5);\n\tif(namestart == 'skin_', removelayer(get(layername)); dec(i); );\n  );\n\u003c/action\u003e\n```\n\n### 动态热点\n\n在 `tour.xml` 空白处的 scene 标签的外面，添加动作代码\n\n```xml\n\u003caction name=\"do_crop_animation\"\u003e\n\t\u003c!-- 为热点注册属性 --\u003e\n\tregisterattribute(xframes, calc((imagewidth / %1) BOR 0));\n\tregisterattribute(yframes, calc((imageheight / %2) BOR 0));\n\tregisterattribute(frames, calc(xframes * yframes));\n\tregisterattribute(frame, 0);\n \n\tset(crop, '0|0|%1|%2');\n \n\tsetinterval(calc('crop_anim_' + name), calc(1.0 / %3),\n\t\tif(loaded,\n\t\t\tinc(frame);\n\t\t\tif(frame GE frames, if(onlastframe !== null, onlastframe() ); set(frame,0); );\n\t\t\tmod(xpos, frame, xframes);\n\t\t\tdiv(ypos, frame, xframes);\n\t\t\tMath.floor(ypos);\n\t\t\tmul(xpos, %1);\n\t\t\tmul(ypos, %2);\n\t\t\tcalc(crop, xpos + '|' + ypos + '|%1|%2');\n\t\t  ,\n\t\t\tclearinterval(calc('crop_anim_' + name));\n\t\t  );\n\t  );\n\u003c/action\u003e\n```\n\n在 `hotspot` 或 `layer` 的代码添加代码， `do_crop_animation(每帧宽,每帧高,fps)`\n\n```xml\nurl=\"explosion.png\"  onloaded=\"do_crop_animation(100,100, 60)\"\n```\n\n### 动态热点添加始终显示的文字\n\n显示 `\u003cscene\u003e title` 中的文字\n\n```xml\n\u003chotspot name=\"spot1\" url=\"animatedhotspot_white.png\" onloaded=\"do_crop_animation(64,64, 60);\"   ath=\"-15\" atv=\"-12\" onclick=\"loadscene(get(linkedscene))\" linkedscene=\"scene_01\"/\u003e\n```\n\n或者在 `\u003chotpsot\u003e text` 中添加显示自定义的文字\n\n```xml\n\u003chotspot name=\"spot1\" url=\"animatedhotspot_white.png\" onloaded=\"do_crop_animation(64,64, 60);\"   ath=\"-15\" atv=\"-12\" onclick=\"loadscene(get(linkedscene))\" text=\"自定义文字\"/\u003e\n```\n\n在热点的 `onload` 事件中加上 `add_all_the_time_tooltip()`\n\n```xml\nonloaded=\"do_crop_animation(64,64, 60);add_all_the_time_tooltip()\"\n```\n\n空白处加上 `action`\n\n```xml\n\u003caction name=\"add_all_the_time_tooltip\"\u003e\n\t    txtadd(tooltipname, 'tooltip_', get(name));\n\t    addplugin(get(tooltipname));\n\t    txtadd(plugin[get(tooltipname)].parent, 'hotspot[', get(name), ']');\n\t    set(plugin[get(tooltipname)].url,'%SWFPATH%/plugins/textfield.swf');\n\t    set(plugin[get(tooltipname)].align,top);\n\t    set(plugin[get(tooltipname)].edge,bottom);\n\t    set(plugin[get(tooltipname)].x,0);\n\t    set(plugin[get(tooltipname)].y,0);\n\t    set(plugin[get(tooltipname)].autowidth,true);\n\t    set(plugin[get(tooltipname)].autoheight,true);\n\t    set(plugin[get(tooltipname)].vcenter,true);\n\t    set(plugin[get(tooltipname)].background,true);\n\t    set(plugin[get(tooltipname)].backgroundcolor,0x000000);\n\t    set(plugin[get(tooltipname)].roundedge,5);\n\t    set(plugin[get(tooltipname)].backgroundalpha,0.65);\n\t    set(plugin[get(tooltipname)].padding,5);\n\t    set(plugin[get(tooltipname)].border,false);\n\t    set(plugin[get(tooltipname)].glow,0);\n\t    set(plugin[get(tooltipname)].glowcolor,0xFFFFFF);\n\t    set(plugin[get(tooltipname)].css,'text-align:center; color:#FFFFFF; font-family:MicrosoftYahei;  font-size:24px;');\n\t    if(device.mobile,set(plugin[get(tooltipname)].css,'text-align:center; color:#FFFFFF; font-family:MicrosoftYahei; font-weight:bold; font-size:24px;');\n\t    \t);\n\t    set(plugin[get(tooltipname)].textshadow,0);\n\t    set(plugin[get(tooltipname)].textshadowrange,6.0);\n\t    set(plugin[get(tooltipname)].textshadowangle,90);\n\t    if(text == '' OR text === null,\n\t    copy(plugin[get(tooltipname)].html,scene[get(linkedscene)].title),\n\t    copy(plugin[get(tooltipname)].html,text)\n\t    );    \n\t    set(plugin[get(tooltipname)].enabled,false);\t\n\u003c/action\u003e\n```\n### 热点和或图层在鼠标点击或鼠标悬停时进入动态模式\n\n```xml\n\u003caction name=\"do_crop_animation_onclick\"\u003e\t\n\t\tif(hotspot[get(name)].animated === null OR hotspot[get(name)].animated == false,\n\t\t    set(hotspot[get(name)].animated,true);\n\t\t\tsetinterval(calc('crop_anim_' + name), calc(1.0 / %3),\t\t\t\n\t\t\t\t\tinc(frame);\n\t\t\t\t\tif(frame GE frames, if(onlastframe !== null, onlastframe() ); set(frame,0); );\n\t\t\t\t\tmod(xpos, frame, xframes);\n\t\t\t\t\tdiv(ypos, frame, xframes);\n\t\t\t\t\tMath.floor(ypos);\n\t\t\t\t\tmul(xpos, %1);\n\t\t\t\t\tmul(ypos, %2);\n\t\t\t\t\tcalc(crop, xpos + '|' + ypos + '|%1|%2');\t\t\t  \t\t\t\t\n\t\t\t  );\n\t\t\t  ,\n            set(hotspot[get(name)].animated,false);  \n\t\t\tclearinterval(calc('crop_anim_' + name));\n\t\t\tset(crop, '0|0|%1|%2');\t\n\t\t  );\n\u003c/action\u003e\n \n\u003caction name=\"do_crop_animation_register\"\u003e\n\t\tregisterattribute(xframes, calc((imagewidth / %1) BOR 0));\n\t\tregisterattribute(yframes, calc((imageheight / %2) BOR 0));\n\t\tregisterattribute(frames, calc(xframes * yframes));\n\t\tregisterattribute(frame, 0);\n\t\tset(crop, '0|0|%1|%2');\t\n\u003c/action\u003e\n \n \n \n\u003c!-- example hotspots --\u003e\n\u003chotspot name=\"spot1\" url=\"animatedhotspot_white.png\" \n\t\tonover=\"do_crop_animation_onclick(64,64,60)\" onout=\"do_crop_animation_onclick(64,64,60)\"   ath=\"-15\" atv=\"-12\" onloaded=\"do_crop_animation_register(64,64)\" /\u003e\n \n\u003chotspot name=\"spot1\" url=\"animatedhotspot_white.png\" \n\t\tonclick=\"do_crop_animation_onclick(64,64,60)\"  ath=\"-15\" atv=\"-12\" onloaded=\"do_crop_animation_register(64,64)\" /\u003e\n```\n\n以上代码执行了一次动态循环后，序列图停留在第一帧，如果只是需要执行一次动态循环，并且序列图停留在最后一帧的话，那么 `do_crop_animation_onclick` 需更改（区别就是 `frame` 这个变量没有重置为 0 ，并且没有重新设置 `crop` ）；\n\n```xml\n\u003caction name=\"do_crop_animation_onclick\"\u003e \n    if(hotspot[get(name)].animated === null OR hotspot[get(name)].animated == false,\n        set(hotspot[get(name)].animated,true);\n      setinterval(calc('crop_anim_' + name), calc(1.0 / %3),  \n \n          inc(frame);\n          if(frame GE frames, if(onlastframe !== null, onlastframe() ); add(frame,frames,-1); );\n          mod(xpos, frame, xframes);\n          div(ypos, frame, xframes);\n          Math.floor(ypos);\n          mul(xpos, %1);\n          mul(ypos, %2);\n          calc(crop, xpos + '|' + ypos + '|%1|%2');               \n        );\n        ,\n        set(hotspot[get(name)].animated,false);  \n      clearinterval(calc('crop_anim_' + name));\n     \n      );\n\u003c/action\u003e\n```\n\n### 拖拽热点\n\n在 `\u003chotspot/\u003e` 中添加代码\n\n```xml\n\tondown=\"draghotspot();\"\n```\n\n添加 action 代码\n\n```xml\n\t\u003caction name=\"draghotspot\"\u003e\n\t\tspheretoscreen(ath, atv, hotspotcenterx, hotspotcentery, 'l');\n\t\tsub(drag_adjustx, mouse.stagex, hotspotcenterx);\n\t\tsub(drag_adjusty, mouse.stagey, hotspotcentery);\n\t\tasyncloop(pressed,\n\t\t\tsub(dx, mouse.stagex, drag_adjustx);\n\t\t\tsub(dy, mouse.stagey, drag_adjusty);\n\t\t\tscreentosphere(dx, dy, ath, atv);\n\t\t  );\n\t\u003c/action\u003e\n```\n\n### 添加简单的全景视频\n\n从 `viewer/examples/videopano` 中复制 `vtourskin.xml`，在主 xml 添加代码\n\n```xml\n\t\u003cscene name=\"videopano\" title=\"户外全景视频\"\u003e\n\t\t\u003c!-- include the videoplayer interface / skin (with VR support) --\u003e\n\t\t\u003cinclude url=\"skin/videointerface.xml\" /\u003e\n\n\t\t\u003c!-- include the videoplayer plugin --\u003e\n\t\t\u003cplugin name=\"video\"\n\t\t        url.html5=\"%SWFPATH%/plugins/videoplayer.js\"\n\t\t        url.flash=\"%SWFPATH%/plugins/videoplayer.swf\"\n\t\t        pausedonstart=\"true\"\n\t\t        loop=\"true\"\n\t\t        volume=\"1.0\"\n\t\t        onloaded=\"add_video_sources();\"\n\t\t        /\u003e\n\n\t\t\u003c!-- use the videoplayer plugin as panoramic image source --\u003e\n\t\t\u003cimage\u003e\n\t\t\t\u003csphere url=\"plugin:video\" /\u003e\n\t\t\u003c/image\u003e\n\n\t\t\u003c!-- set the default view --\u003e\n\t\t\u003cview hlookat=\"0\" vlookat=\"0\" fovtype=\"DFOV\" fov=\"130\" fovmin=\"75\" fovmax=\"150\" distortion=\"0.0\" /\u003e\n\n\t\t\u003c!-- add the video sources and play the video --\u003e\n\t\t\u003caction name=\"add_video_sources\"\u003e\n\t\t\tvideointerface_addsource('1024x512', '%CURRENTXML%/video/video-1024x512.mp4|%CURRENTXML%/video/video-1024x512.webm|%CURRENTXML%/video/iphone-audio.m4a', '%CURRENTXML%/video/video-1024x512-poster.jpg');\n\t\t\tvideointerface_addsource('1920x960', '%CURRENTXML%/video/video-1920x960.mp4|%CURRENTXML%/video/video-1920x960.webm|%CURRENTXML%/video/iphone-audio.m4a', '%CURRENTXML%/video/video-1920x960-poster.jpg');\n\t\t\t\n\t\t\tif(device.ios,\n\t\t\t\t\u003c!-- iOS Safari has a very slow 'video-to-webgl-texture' transfer, therefore use a low-res video by default --\u003e\n\t\t\t\tvideointerface_play('1024x512');\n\t\t\t  ,\n\t\t\t\tvideointerface_play('1920x960');\n\t\t\t  );\n\t\t\u003c/action\u003e\n\t\u003c/scene\u003e\n```\n \n### 添加雨雪特效\n\n1. 添加文件 [https://pan.baidu.com/s/12Dkr2jeAWVmzbzE5RrU0RA][snow] 密码：gyrc \n  \n2. 在 `viewer\\plugins` 拷贝 `snow.swf` 和 `snow.js`  \n\n3. 添加  `\u003cscene onstart=\"snowballs();\"\u003e`  \n\t\n\t目前可选的特效\n\t- 默认雪 `onstart='defaultsnow();'`\n\t- 雪球 `onstart='snowball();'`\n\t- 雪花 `onstart='snowflakes();'`\n\t- 银色星星 `onstart='silverstars();'`\n\t- 金色星星 `onstart='goldenstars();'`\n\t- 心形 `onstart='hearts();'`\n\t- 笑脸 `onstart='smileys();'`\n\t- 钱 `onstart='money();'`\n\t- 雨 `onstart='rain();'`\n\t- 大雨 `onstart='heavyrain();'`\n\n4. 在 `\u003cscene\u003e` 添加代码\n\n```xml\n\u003cinclude url=\"snow.xml\" /\u003e\n``` \n\n### 自动旋转\n\n添加代码\n\n```xml\n\u003cautorotate enabled=\"true\"\nwaittime=\"5.0\"\nspeed=\"-3.0\"\nhorizon=\"0.0\"\ntofov=\"120.0\"\n/\u003e\n```\n- `waittime` 代表在最近一次用户交互行为之后要开始自动旋转之前的等待时间。以秒为单位；\n- `speed` 为旋转速度。当该数值为正值时向右旋转，为负值时向左旋转；\n- `horizon` 为场景在自动旋转时将达到的水平位置；\n- `tofov` 为旋转中要达到的视场角。\n\n\n### 无按钮控制的自动旋转\n自动旋转场景，场景旋转一圈后自动进入下一个场景，最后一个场景浏览结束后，进入第一个场景。需添加如下代码：\n\n```xml\n\u003cautorotate enabled=\"true\"\nwaittime=\"5.0\"\nspeed=\"-3.0\"\nhorizon=\"0.0\"\ntofov=\"120.0\"\n/\u003e\n```\n\n修改 `\u003caction name=\"startup/\u003e` 中的代码\n\n```xml\n\u003caction name=\"startup\"\u003e\nif(startscene === null, copy(startscene,scene[0].name));\nloadscene(get(startscene), null, MERGE);\nif(autorotate.enabled,bombtimer(0));\n\u003c/action\u003e\n```\n\n在 `xml` 文件中加入下面的代码\n\n```xml\n\u003cevents onmousedown=\"set(bt,0);\" /\u003e\n\u003caction name=\"bombtimer\"\u003e\nset(autorotate.enabled,true);\nset(bt,%1);\nadd(bt,1);\ndelayedcall(1, bombtimer(get(bt)));\ncopy(bt_1,autorotate.speed);\nMath.abs(bt_1);\ndiv(bt_2,360,bt_1);\nadd(bt_2,autorotate.waittime);\nif(bt GE bt_2, set(bt,0); nextscene(););\n\u003c/action\u003e\n\u003caction name=\"nextscene\"\u003e\nset(ns, get(scene[get(xml.scene)].index));\nset(maxs, get(scene.count));\nadd(ns,1);\nif(ns == maxs, set(ns,0));\nloadscene(get(scene[get(ns)].name), null, MERGE, BLEND(1.5));\n\u003c/action\u003e\n```\n\n### 按钮控制的自动旋转\n添加代码\n\n```xml\n\u003cautorotate enabled=\"true\"\nwaittime=\"5.0\"\nspeed=\"-3.0\"\nhorizon=\"0.0\"\ntofov=\"120.0\"\n/\u003e\n```\n\n在对应的按钮，通常为 `\u003clayer\u003e` 标签中找到 `onclick` 属性替换，如果没有则直接添加\n\n```xml\n\u003clayer ... onclick=\"switch(autorotate.enabled);\" ... /\u003e\n```\n\n### 添加陀螺仪\n\n加载插件（此方法与上述隐藏皮肤的方法冲突）\n\n```xml\n\u003cplugin name=\"gyro\" devices=\"html5\"\n\t        url=\"%SWFPATH%/plugins/gyro2.js\"\n\t        enabled=\"false\"\n                onavailable=\"gyro_available_info();\"\n\t        /\u003e\n \n\u003caction name=\"gyro_available_info\"\u003e\n\t\tset(layer[gyrobutton].visible, true);\n\u003c/action\u003e\n```\n\n控制按钮\n\n```xml\n\u003clayer name=\"gyrobutton\" url=\"gyroicon.png\" scale=\"0.5\" align=\"right\" x=\"10\" visible=\"false\" \n\t\t       onclick=\"switch(plugin[gyro].enabled);\"\n\t\t       /\u003e\n```\n\n默认皮肤开启陀螺仪功能（在 `tour.xml` 的 `skin_settings`中设置）\n\n```\ngyro=\"true\"\n```\n\n在 `tour.xml` 的 `include` 的下一行添加\n\n```xml\n\u003cplugin name=\"skin_gyro\" \n\t\tenabled=\"true\"\n\t\tcamroll=\"false\"\n   \t\tonenable=\"set(view.limitview, range);\"\n\t\t/\u003e\n```\n\n### 场景过渡效果\n\n修改全部过渡效果，只需修改 `\u003cskin_settings /\u003e` 中以下代码。\n\n```xml\nloadscene_blend=\"OPENBLEND(0.5, 0.0, 0.75, 0.05, linear)\"\nloadscene_blend_prev=\"SLIDEBLEND(0.5, 180, 0.75, linear)\"\nloadscene_blend_next=\"SLIDEBLEND(0.5,   0, 0.75, linear)\"\n```\n如果想为某个特殊的 `loadscene` 动作加上不一样的过渡效果，在主 `xml` 的 `scene` 外加入以下代码\n\n```xml\n\u003cblendmodes name=\"no blending\"       description=\"无过渡效果\"  blend=\"NOBLEND\" /\u003e\n\u003cblendmodes name=\"simple crossblending\" description=\"简单淡入淡出\" blend=\"BLEND(1.0, easeInCubic)\" /\u003e\n\u003cblendmodes name=\"zoom blend\"        description=\"缩放过渡\"  blend=\"ZOOMBLEND(2.0, 2.0, easeInOutSine)\" /\u003e\n\u003cblendmodes name=\"black-out\"         description=\"黑场过渡\"  blend=\"COLORBLEND(2.0, 0x000000, easeOutSine)\" /\u003e\n\u003cblendmodes name=\"white-flash\"       description=\"白场过渡\"  blend=\"LIGHTBLEND(1.0, 0xFFFFFF, 2.0, linear)\" /\u003e\n\u003cblendmodes name=\"right-to-left\"     description=\"从右至左\"  blend=\"SLIDEBLEND(1.0, 0.0, 0.2, linear)\" /\u003e\n\u003cblendmodes name=\"top-to-bottom\"     description=\"从上至下\"   blend=\"SLIDEBLEND(1.0, 90.0, 0.01, linear)\" /\u003e\n\u003cblendmodes name=\"diagonal\"          description=\"对角线\"     blend=\"SLIDEBLEND(1.0, 135.0, 0.4, linear)\" /\u003e\n\u003cblendmodes name=\"circle open\"       description=\"圆形展开\"      blend=\"OPENBLEND(1.0, 0.0, 0.2, 0.0, linear)\" /\u003e\n\u003cblendmodes name=\"vertical open\"     description=\"垂直展开\"     blend=\"OPENBLEND(0.7, 1.0, 0.1, 0.0, linear)\" /\u003e\n\u003cblendmodes name=\"horizontal open\"   description=\"水平展开\"    blend=\"OPENBLEND(1.0, -1.0, 0.3, 0.0, linear)\" /\u003e\n\u003cblendmodes name=\"elliptic + zoom\"   description=\"椭圆缩放\"      blend=\"OPENBLEND(1.0, -0.5, 0.3, 0.8, linear)\" /\u003e\n```\n\n修改 `loadscene(scenename, null, MERGE, get(blendmodes[black-out].blend));`\n\n```xml\n\u003chotspot onclick=\"loadscene(scene_shuilifang, null, MERGE, get(blendmodes[vertical open].blend));\" /\u003e\n```\n\n### 隐藏显示热点\n添加 `\u003caction\u003e`\n\n```xml\n\u003caction name=\"hideBox\"\u003e\n  tween(%1.alpha,0,0.5);\n  wait(1);\n  set(%1.visible,false);\n\u003c/action\u003e\n\n\u003caction name=\"showBox\"\u003e\n  set(%1.alpha,0);\n  set(%1.visible,true);\n  tween(%1.alpha,1,0.5);\n  tween(%1.scale,1,0.5,easeOutBack);\n\u003c/action\u003e\n```\n\n使用\n```xml\n\u003chotspot name=\"spot1\" style=\"skin_hotspotstyle\" ath=\"46.131\" atv=\"24.389\" visible=\"true\" onclick=\"spot1Click\" /\u003e\n\u003caction name=\"spot1Click\"\u003e\n\thideBox(hotspot[spot1]);\n\u003c/action\u003e\n```\n\n### 获取全景视频进度\n\n```xml\n\u003c!-- 获取视频进度 --\u003e\n\u003caction name=\"get_video_time\"\u003e\n  setinterval(skin_video_seek_updates0, 0.1, skin_video_updatetime0())\n\u003c/action\u003e\n\n\u003caction name=\"skin_video_updatetime0\"\u003e\n  setStop(4,video_pause_events(););\n\u003c/action \u003e\n\t\t\n\u003caction name=\"setStop\"\u003e\n  copy(t1, plugin[video].time);\n  if(t1 GT %1,%2);\n\u003c/action\u003e\n \n\u003c!-- 视频暂停回调 --\u003e\n\u003caction name=\"video_pause_events\"\u003e\n  plugin[video].pause();\n  clearinterval(skin_video_seek_updates0);\n\u003c/action\u003e\n```\n\n### 用 js 控制场景跳转\n\n\n```javascript\n// 场景跳转 index:0,1,2\nfunction krpanoTo(index){\n\tvar krpano = document.getElementById(\"krpanoSWFObject\");\n\t// 跳转到场景1\n\tif(index == 0){ krpano.call(\"to0\"); }\n\t// 跳转到场景2\n\tif(index == 1){ krpano.call(\"to1\"); }\n\t// 跳转到场景3\n\tif(index == 2){ krpano.call(\"to2\"); }\n}\n```\n\n```xml\n\u003caction name=\"to0\"\u003e\n\tloadscene(\"scene_index1\", null, MERGE);\n\u003c/action\u003e\n\n\u003caction name=\"to1\"\u003e\n\tloadscene(\"scene_index2\", null, MERGE);\n\u003c/action\u003e\n\n\u003caction name=\"to2\"\u003e\n\tloadscene(\"scene_index3\", null, MERGE);\n\u003c/action\u003e\n```\n\n## 总结\n以上为自己在学习与开发过程中记录的笔记，欢迎多多交流。\n\n### 参考链接\n- 参考链接 1： https://krpano.milly.me/\n- 参考链接 2： http://www.krpano360.com/\n\n[link1]:https://krpano.milly.me/\n[link2]:http://www.krpano360.com/\n[github]:https://github.com/NalvyBoo/nodeKrpano/\n[snow]:https://pan.baidu.com/s/12Dkr2jeAWVmzbzE5RrU0RA\n[demo]:http://go.163.com/2015/public/team/ningbo/krpano/comn01/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fningbonb%2Fnodekrpano","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fningbonb%2Fnodekrpano","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fningbonb%2Fnodekrpano/lists"}