lateri 4 vuotta sitten
vanhempi
commit
74f280c1d7
54 muutettua tiedostoa jossa 9622 lisäystä ja 35 poistoa
  1. 2 7
      smty/index.html
  2. 357 0
      smty/js/index.js
  3. 0 1
      smty/js/index.min.js
  4. 2283 0
      smty/js/smty.js
  5. 0 1
      smty/js/smty.min.js
  6. 572 0
      smty/js/ybf.js
  7. 0 1
      smty/js/ybf.min.js
  8. 5 0
      smty/lib/plugins/bingmaps.js
  9. BIN
      smty/lib/plugins/bingmaps.swf
  10. 522 0
      smty/lib/plugins/combobox.xml
  11. 48 0
      smty/lib/plugins/doubleclick_style.xml
  12. 28 0
      smty/lib/plugins/fps.xml
  13. 5 0
      smty/lib/plugins/googlemaps.js
  14. 5 0
      smty/lib/plugins/gyro2.js
  15. 5 0
      smty/lib/plugins/pp_blur.js
  16. 5 0
      smty/lib/plugins/pp_light.js
  17. 5 0
      smty/lib/plugins/pp_sharpen.js
  18. 19 0
      smty/lib/plugins/scrollarea.js
  19. BIN
      smty/lib/plugins/scrollarea.swf
  20. 214 0
      smty/lib/plugins/showtext.xml
  21. 5 0
      smty/lib/plugins/soundinterface.js
  22. BIN
      smty/lib/plugins/soundinterface.swf
  23. 5 0
      smty/lib/plugins/videoplayer.js
  24. BIN
      smty/lib/plugins/videoplayer.swf
  25. 5 0
      smty/lib/plugins/webvr.js
  26. 923 0
      smty/lib/plugins/webvr.xml
  27. BIN
      smty/lib/plugins/webvr_handcursor.png
  28. BIN
      smty/lib/plugins/webvr_laser.png
  29. BIN
      smty/lib/plugins/webvr_light.png
  30. BIN
      smty/lib/plugins/webvr_vrcursor.png
  31. BIN
      smty/lib/skin/rotate_device.png
  32. BIN
      smty/lib/skin/vtourskin.png
  33. 1333 0
      smty/lib/skin/vtourskin.xml
  34. 28 0
      smty/lib/skin/vtourskin_design_117.xml
  35. 31 0
      smty/lib/skin/vtourskin_design_117round.xml
  36. 71 0
      smty/lib/skin/vtourskin_design_black.xml
  37. 42 0
      smty/lib/skin/vtourskin_design_flat_light.xml
  38. 40 0
      smty/lib/skin/vtourskin_design_glass.xml
  39. 58 0
      smty/lib/skin/vtourskin_design_ultra_light.xml
  40. BIN
      smty/lib/skin/vtourskin_hotspot.png
  41. BIN
      smty/lib/skin/vtourskin_light.png
  42. BIN
      smty/lib/skin/vtourskin_mapspot.png
  43. BIN
      smty/lib/skin/vtourskin_mapspotactive.png
  44. 801 0
      smty/lib/tween.umd.js
  45. 131 0
      smty/lib/vector.js
  46. 4 2
      smty/smty.html
  47. 1 4
      smty/tip.html
  48. 3 10
      smty/ybf.html
  49. 3 1
      yljq/index.html
  50. 381 0
      yljq/js/index.js
  51. 0 1
      yljq/js/index.min.js
  52. 1674 0
      yljq/js/ypano.js
  53. 0 1
      yljq/js/ypano.min.js
  54. 8 6
      yljq/ypano.html

+ 2 - 7
smty/index.html

@@ -24,8 +24,6 @@
             font-family:  "Microsoft YaHei";  
             width: 1280px;
             height:720px;
-            /* background-repeat:no-repeat; */
-            /* width: 120vw; */
             
 }
 
@@ -99,10 +97,7 @@
 
 
     <div id='listContent_ybf'>
-        <!-- <div class="pano">
-            <div class="title"></div>
-            <div class="thumb"><img  src='panos/01frontGate4k_b.jpg' /></div>
-        </div> -->
+
     </div>
 
 
@@ -110,7 +105,7 @@
 
     <div class="ctrlBtn"></div>
 
-    <script src="./js/index.min.js"></script>
+    <script src="./js/index.js"></script>
 
     <script type="text/javaScript">
 

+ 357 - 0
smty/js/index.js

@@ -0,0 +1,357 @@
+
+var isUserInteracting = false,
+onMouseDownMouseX = 0,
+onMouseDownMouseY = 0,
+lon = 0,
+onMouseDownLon = 0,
+lat = 0,
+onMouseDownLat = 0,
+phi = 0,
+theta = 0;
+
+const house ={
+    idx:0,
+    nextId:null,
+    title:'南京世茂项目',
+    backurl:'',
+    descript:'',
+    is_yuyue:false,
+    yy_step:0,
+    src:[
+    {id:0,name:"Kanfang",title:'',thumb:"nanimages/yykf_sel.png"},
+    {id:1,name:"01frontGate",title:'A1户型 建面约165m2',thumb:"nanimages/sc_1.jpg"},
+    {id:2,name:"02masterBedroom",title:'B1户型 建面约187m2',thumb:"nanimages/sc_2.jpg"},
+    {id:3,name:"03masterBedroom",title:'C1户型 建面约210m2',thumb:"nanimages/sc_3.jpg"},
+    {id:4,name:"04masterBedroom",title:'D1户型 建面约215m2',thumb:"nanimages/sc_4.jpg"},
+
+],
+
+} 
+
+
+init()
+
+
+function init(){
+
+    const queryString = window.location.search;
+
+    const urlParams = new URLSearchParams(queryString);
+
+    let backurl= urlParams.get('backurl')?urlParams.get('backurl'):'../'
+
+    house.backurl = backurl
+
+
+
+
+    var listContent_ybf=document.getElementById("listContent_ybf");
+    while (listContent_ybf.firstChild) {
+        listContent_ybf.removeChild(listContent_ybf.firstChild);
+    }
+
+    let mid = 0
+
+    for(let item of house.src){
+
+
+        const dpano = document.createElement("div");
+        dpano.className = 'pano'
+
+        // if(item.id==0){
+        //     dpano.className = 'panoSelect'
+        // }
+
+        mid = item.id
+
+        if(mid==1){
+            dpano.style.marginLeft=0
+        }
+        
+        dpano.setAttribute('data-id',mid);
+        const title = document.createElement("div");
+        title.className = 'title'
+        title.innerHTML = item.title
+        const thumb = document.createElement("div");
+        thumb.className =  item.id===0?'kanfang': 'thumb'
+        // thumb.className ='thumb'
+        // thumb.innerHTML = house.src[i].name
+        const img=document.createElement("img");
+
+        if(item.id==0){
+            img.id= 'kanfang_image'
+        }
+
+        img.src= item.thumb
+
+        thumb.appendChild(img);
+
+        dpano.appendChild(title);
+        dpano.appendChild(thumb);
+
+        listContent_ybf.appendChild(dpano);
+    }
+
+
+    document.getElementById("yd_phone").addEventListener('change', onChange, false);
+}
+
+function onChange(e){
+    console.log(e)
+
+}
+
+
+function selectUpnDown(is_down){
+    if(house.yy_step==1){
+        if(is_down){
+            document.getElementById('yuyue_ok').src ='./nanimages/qd_sel.png';
+            document.getElementById('yuyue_ok').setAttribute('data-sel',true);
+            document.getElementById("yd_phone").blur();
+        }else{
+            document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+            document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+    
+            document.getElementById('yd_phone').focus();
+        }
+    }   
+    
+}
+
+function limitWords(txt){
+    var str = txt;
+    if(str.length>180){
+        str = str.substr(0,180) + '...';
+    }
+    
+    return str;
+}
+
+function selectLeftnRight(is_right){
+
+    const nodess = document.getElementById("listContent_ybf").childNodes;
+
+    let is_kanfang = true
+
+    for(let i =0;i<nodess.length;i++){
+        nodess[i].className = 'pano'
+    }
+
+    if(is_right){
+        pano_select = house.idx===nodess.length -1? 0:house.idx+1
+    }else{
+        pano_select = house.idx===0? nodess.length -1:house.idx-1
+    }
+
+    if(pano_select===0){
+        document.getElementById("kanfang_image").src='./nanimages/yykf_sel.png'
+    }else{
+        document.getElementById("kanfang_image").src='./nanimages/yykf_non.png'
+        nodess[pano_select].className='panoSelect'
+    }
+
+    house.idx = pano_select
+}
+
+function enterPano(){
+
+
+        const backurl = house.backurl
+
+        const url = "ybf.html?&backurl="+backurl
+
+        window.location.href = url 
+
+
+}
+
+
+
+
+
+// function onKeyUp(e){
+//     switch(e.keyCode){
+//         // case 38://ArrowUp
+//         //     selectUpnDown(false)
+//         //     break
+//         // case 40://ArrowDown
+//         //     selectUpnDown(true)
+//         //     break
+//         case 37: //ArrowLeft
+//             selectLeftnRight(false)
+//             break
+//         case 39://ArrowRight
+//             selectLeftnRight(true)
+//             break
+//         case 13://Enter
+//             // 
+//         case 48: // auto play
+//             break
+//         case 49:
+//             break
+//         default:
+//             break
+//     }
+// }
+
+
+function startYuYue(){
+    const is_sel = document.getElementById('yuyue_ok').getAttribute('data-sel');
+
+    switch(house.yy_step){
+        case 0:
+            house.yy_step++
+
+            house.is_yuyue = true
+            document.getElementById("kanfang_yuding").style.display='flex'
+            document.getElementById("yd_phone").style.display = 'flex'
+            document.getElementById('yd_phone').focus();
+            break
+        case 1:
+            
+            if(is_sel=='true'){
+
+                const phone = document.getElementById('yd_phone').value
+                if(phone.length==0){
+                    house.yy_step = 0
+                    document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+                    document.getElementById("kanfang_yuding").style.display='none'
+                    document.getElementById("yd_phone").style.display = 'flex'
+                    document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+                    document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+                    house.is_yuyue = false
+                }else{
+                    house.yy_step++
+                    document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yy_success.png)";
+                    document.getElementById("yd_phone").style.display = 'none'
+                }
+            }
+
+            break
+        case 2:
+            
+            if(is_sel=='true'){
+                house.yy_step = 0
+                document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+                document.getElementById("kanfang_yuding").style.display='none'
+                document.getElementById("yd_phone").style.display = 'flex'
+                document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+                document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+                // document.getElementById('yd_phone').focus();
+                house.is_yuyue = false
+            }
+
+            break
+    }
+}
+
+
+var btn = new tvSysBtnBind({
+    id: "Jdoc",
+    className: "ctrlBtn",
+    currentClass: "current",
+    keyRemoveDefault: false,
+    effect: "base",
+    currentIndex: 0,
+    onLoad: function(e) {
+
+    },
+    onPress:function() {
+        var keyCode = this.event.keyCode;
+        // alert('tvSysBtnBind:'+keyCode+" - " + this.event.key)
+        // console.log('tvSysBtnBind:'+keyCode+" - " + this.event.key)
+        switch (keyCode) {
+            case 37: // left
+            // reloadData();
+            selectLeftnRight(false)
+            break;
+            case 39: // right
+            selectLeftnRight(true)
+            break;
+            case 38: //up
+                 selectUpnDown(false)
+            break;
+            case 40: //down
+                selectUpnDown(true)
+            break;
+            // case 13: //enter
+            
+            // break;
+            case 33: //chanel +
+            
+            break;
+            case 34: //chanel -
+            
+            break;
+            case 48: //0
+            
+            break;
+            default:
+                break;
+        }
+    },
+    onEnterPress: function() {
+
+
+        if(house.idx==0){
+            
+            startYuYue()
+        }else{
+            enterPano()
+        }
+        
+    },
+    onBack: function() {
+    // console.log(window.UtilToJS)
+        // if(typeof(VrBrowserToJS)!=='undefined'){
+        //     // UtilToJS.appExit();
+        //     // VrBrowserToJS.vrBrowerExit();
+        //     VrBrowserToJS.vrBrowserExit();
+
+        //     // VrBrowserToJS.appExit()
+        // }
+        // document.getElementById('debug').innerHTML +="<br>" +'onBack'
+        console.log(house.is_yuyue)
+        if(!house.is_yuyue){
+            const backurl = house.backurl
+
+            console.log('backurl')
+            window.location.href = backurl 
+        }else{
+
+            // document.getElementById('debug').innerHTML +="<br>" +'house.yy_step'+house.yy_step
+            console.log('house.yy_step',house.yy_step)
+            if(house.yy_step==1){
+                const phone = document.getElementById('yd_phone').value
+                const qy_phone = phone.length>1?phone.substring(0,phone.length-1):''
+                document.getElementById('yd_phone').value = qy_phone
+            }else{
+
+            }
+        }
+
+        
+
+    }
+});
+
+window.onBackEvent= function(){
+    // document.getElementById('debug').innerHTML +="<br>" +'window.onBackEvent'
+    if(!house.is_yuyue){
+        const backurl = house.backurl
+        console.log('backurl')
+        window.location.href = backurl 
+    }else{
+        house.yy_step = 0
+        document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+        document.getElementById("kanfang_yuding").style.display='none'
+        document.getElementById("yd_phone").style.display = 'flex'
+        document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+        document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+        // document.getElementById('yd_phone').focus();
+        house.is_yuyue = false
+
+
+    }
+
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 1
smty/js/index.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2283 - 0
smty/js/smty.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 1
smty/js/smty.min.js


+ 572 - 0
smty/js/ybf.js

@@ -0,0 +1,572 @@
+
+var isUserInteracting = false,
+onMouseDownMouseX = 0,
+onMouseDownMouseY = 0,
+lon = 0,
+onMouseDownLon = 0,
+lat = 0,
+onMouseDownLat = 0,
+phi = 0,
+theta = 0;
+
+const house ={
+    idx:0,
+    nextId:null,
+    select_status:0,
+    yy_step:0,
+    is_yuyue:false,
+    title:'A1户型 建面约165m2',
+    descript:'<b>塔尖</b>:三重入户礼序/私宴、会客、社交厨房空间一体化以<br/>\
+    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 奢华套房规制客居空间 <br/>\
+    <b>天际</b>:宽景阳台,揽城市繁华万象<br/>\
+    <b>想象</b>:约1m2家政间释放空间自由/主卧步入式衣帽间,定制<br/>\
+    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 情境式时装廊',
+    // img:'./panosimages/0.png',
+    src:[
+    
+        {id:1,name:"01frontGate",title:'01正门',thumb:"panos/01frontGate_b.jpg",descript:'简介:01正门于俄罗斯北部,波罗的海沿岸...'},
+    {id:2,name:"02masterBedroom",title:'02主卧',thumb:"panos/02masterBedroom_b.jpg",descript:'简介:02主卧位于俄罗斯北部,波罗的海沿岸...'},
+    {id:3,name:"03masterBedroom",title:'03主卧',thumb:"panos/03masterBedroom_b.jpg",descript:'简介:03主卧位于俄罗斯北部,波罗的海沿岸...'},
+    {id:4,name:"04masterBedroom",title:'04主卧',thumb:"panos/04masterBedroom_b.jpg",descript:'简介:04主卧于俄罗斯北部,波罗的海沿岸...'},
+    {id:5,name:"05masterBedroomToilet",title:'05主卧卫生间',thumb:"panos/05masterBedroomToilet_b.jpg",descript:'简介:05主卧卫生间位于俄罗斯北部,波罗的海沿岸...'},
+    {id:6,name:"06masterBedroomPorch",title:'06主卧门廊',thumb:"panos/06masterBedroomPorch_b.jpg",descript:'简介:06主卧门廊位于俄罗斯北部,波罗的海沿岸...'},
+    {id:7,name:"07masterBedroomCloakroom",title:'07主卧衣帽间',thumb:"panos/07masterBedroomCloakroom_b.jpg",descript:'简介:07主卧衣帽间位于俄罗斯北部,波罗的海沿岸...'},
+    {id:8,name:"08AguestRoom",title:'08客房',home:{T:90,R:100},thumb:"panos/08AguestRoom_b.jpg",descript:'简介:08客房于俄罗斯北部,波罗的海沿岸...'},
+    {id:9,name:"09guestRoomA",title:'09客房A',home:{T:80,R:90},thumb:"panos/09guestRoomA_b.jpg",descript:'简介:09客房A于俄罗斯北部,波罗的海沿岸...'},
+    {id:10,name:"10guestRoomAToilet",title:'10客房卫生间',home:{T:70,R:100},thumb:"panos/10guestRoomAToilet_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:11,name:"11guestRoomB",title:'11客房B',home:{T:85,R:70},thumb:"panos/11guestRoomB_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:12,name:"12guestRoomB",title:'12客房B',home:{T:80,R:60},thumb:"panos/12guestRoomB_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:13,name:"13guestRoomB",title:'13客房B',home:{T:95,R:70},thumb:"panos/13guestRoomB_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:14,name:"14livingRoom",title:'14客厅',home:{T:20,R:70},thumb:"panos/14livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:15,name:"15livingRoom",title:'15客厅',home:{T:30,R:50},thumb:"panos/15livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:16,name:"16livingRoom",title:'16客厅',home:{T:20,R:50},thumb:"panos/16livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:17,name:"17livingRoom",title:'17客厅',home:{T:8,R:60},thumb:"panos/17livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:18,name:"18livingRoom",title:'18客厅',home:{T:8,R:40},thumb:"panos/18livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:19,name:"19livingRoom",title:'19客厅',home:{T:8,R:50},thumb:"panos/19livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:20,name:"20livingRoom",title:'20客厅',home:{T:40,R:45},thumb:"panos/20livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:21,name:"21livingRoom",title:'21客厅',home:{T:42,R:55},thumb:"panos/21livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:22,name:"22livingRoom",title:'22客厅',home:{T:23,R:20},thumb:"panos/22livingRoom_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:23,name:"23kitchen",title:'23厨房',home:{T:-5,R:65},thumb:"panos/23kitchen_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:24,name:"24laundry",title:'24洗衣间',home:{T:-5,R:40},thumb:"panos/24laundry_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+    {id:25,name:"25frontGatePorch",title:'25前门门廊',home:{T:65,R:75},thumb:"panos/25frontGatePorch_b.jpg",descript:'简介:圣彼得堡位于俄罗斯北部,波罗的海沿岸...'},
+],
+
+} 
+
+
+init()
+
+
+function init(){
+
+    const queryString = window.location.search;
+
+    const urlParams = new URLSearchParams(queryString);
+
+    let pano_Id = urlParams.get('id')?urlParams.get('id'):-1
+
+    let backurl= urlParams.get('backurl')?urlParams.get('backurl'):'../'
+
+    let panoId = pano_Id>house.src.length?house.src.length-1:pano_Id
+
+    const descriptContent=document.getElementById("descriptContent");
+    descriptContent.innerHTML = limitWords(house.descript)
+    
+    if(panoId!==-1){
+        // update conver
+        const conver = document.getElementById('cover')
+        // conver.src='./panos/'+house.src[panoId].name +"1k_f.jpg"
+        conver.setAttribute('data-id',panoId)
+        conver.setAttribute('data-backurl',backurl)
+
+        const playdiv = document.getElementById('play')
+        playdiv.style.backgroundImage='url("./nanimages/play4.png")'
+
+    }else{
+        panoId  =0
+        const conver = document.getElementById('cover')
+        // // conver.src='panos/'+house.src[house.idx].name +"1k_f.jpg"
+        conver.setAttribute('data-id',panoId)
+        conver.setAttribute('data-backurl',backurl)
+
+        const playdiv = document.getElementById('play')
+        playdiv.style.backgroundImage='url("./nanimages/play_click.png")'
+
+
+    
+    }
+
+    house.idx = panoId
+
+    console.log('panoId',panoId)
+
+    const listTitle = document.getElementById('listTitle')
+    listTitle.innerHTML = "剧集列表("+ house.src.length +"集全)"
+
+    var listContent=document.getElementById("listContent");
+    while (listContent.firstChild) {
+        listContent.removeChild(listContent.firstChild);
+    }
+
+    let mid = 0
+
+    for(let item of house.src){
+
+
+        const dpano = document.createElement("div");
+        dpano.className = 'pano'
+
+        if(item.id-1==pano_Id*1){
+            dpano.className = 'panoSelect'
+        }
+
+        mid = item.id
+
+        if(mid==1){
+            dpano.style.marginLeft=0
+        }
+        
+
+        dpano.setAttribute('data-id',mid);
+        const title = document.createElement("div");
+        title.className = 'title'
+        title.innerHTML = item.title
+        const thumb = document.createElement("div");
+        thumb.className = 'thumb'
+        // thumb.innerHTML = house.src[i].name
+        const img=document.createElement("img");
+
+        img.src= './thumb1k/'+item.name + '1k_f.jpg';
+
+        thumb.appendChild(img);
+
+        dpano.appendChild(title);
+        dpano.appendChild(thumb);
+
+        listContent.appendChild(dpano);
+    }
+
+    // const ddiv = document.createElement("div");
+    // ddiv.innerHTML='.'
+    // ddiv.className = 'panoEnd'
+    // listContent.appendChild(ddiv);
+
+    if(pano_Id!=-1){
+
+        const offset = document.getElementsByClassName("thumb")
+            const offset_width = offset.length>1&&offset[1].clientWidth?offset[1].clientWidth:200
+
+            // document.getElementById('listContent').scrollLeft =offset_width*pano_select;
+            const fromLeft = document.getElementById('listContent').scrollLeft
+            const toLeft = offset_width*pano_Id
+
+            const coords = {x: fromLeft, y: 0} // Start at (0, 0)
+            const tween = new TWEEN.Tween(coords) // Create a new tween that modifies 'coords'.
+                .to({x: toLeft, y: 200}, 1000) // Move to (300, 200) in 1 second.
+                .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
+                .onUpdate(() => {
+                    // Called after tween.js updates 'coords'.
+                    // Move 'box' to the position described by 'coords' with a CSS translation.
+                    document.getElementById('listContent').scrollLeft = coords.x
+                })
+                .start() // Start the tween immediately.
+
+    }
+
+     //防止页面后退
+    //  history.pushState(null, null, document.URL);
+    //  window.addEventListener('popstate', function () {
+    //          history.pushState(null, null, document.URL);
+    //  });
+
+
+    // document.addEventListener('keyup', onKeyUp);
+
+    document.getElementById('play').addEventListener('click', enterPano);
+
+    // const Jdoc=document.getElementById("Jdoc");
+    // Jdoc.style.backgroundSize = "1280px 720px";
+
+}
+
+function Quit(){
+
+    // window.removeEventListener('popstate', function () {
+    //         history.pushState(null, null, document.URL);
+    // });
+    document.getElementById('play').removeEventListener('click', enterPano);
+    // document.removeEventListener('keyup');
+    // document.getElementById('play').removeEventListener('click');
+    // window.removeEventListener('popstate');
+
+}
+
+
+
+function selectUpnDown(is_down){
+
+    if(house.yy_step==1){
+        if(is_down){
+            document.getElementById('yuyue_ok').src ='./nanimages/qd_sel.png';
+            document.getElementById('yuyue_ok').setAttribute('data-sel',true);
+            document.getElementById("yd_phone").blur();
+        }else{
+            document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+            document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+    
+            document.getElementById('yd_phone').focus();
+        }
+    }  else{
+        const nodess = document.getElementById("listContent").childNodes;
+        for(let i =0;i<nodess.length-1;i++){
+            if(nodess[i].className==='panoSelect'){
+                nodess[i].className = 'pano'
+            } 
+        }
+    
+        if(is_down){
+            const firstChild = document.getElementById('listContent').firstChild
+            firstChild.className = 'panoSelect'
+    
+            const playdiv = document.getElementById('play')
+            playdiv.style.backgroundImage='url("./nanimages/play4.png")'
+
+            document.getElementById('ybf_yuyue').style.backgroundImage='url("./nanimages/yykf2_non.png")'
+    
+            document.getElementById('listContent').scrollLeft =0;
+
+
+
+    
+            let panoId = 0
+    
+            // document.getElementById('descriptTitle').innerHTML = house.src[panoId].title
+            // document.getElementById('descriptContent').innerHTML = limitWords(house.src[panoId].descript)
+    
+            // update conver
+            // const conver = document.getElementById('cover')
+            // conver.src='./panos/'+house.src[panoId].name +"4k_f.jpg"
+            // conver.setAttribute('data-id',panoId)
+    
+    
+    
+        }else{
+            const playdiv = document.getElementById('play')
+            // playdiv.className = 'playSelect'
+            playdiv.style.backgroundImage='url("./nanimages/play_click.png")'
+    
+        }
+
+    }
+
+}
+
+function limitWords(txt){
+    var str = txt;
+    if(str.length>280){
+        str = str.substr(0,280) + '...';
+    }
+    
+    return str;
+}
+
+function selectLeftnRight(is_right){
+
+    const nodess = document.getElementById("listContent").childNodes;
+
+    let is_yuyue = true
+    house.select_status = 0
+
+    for(let i =0;i<nodess.length;i++){
+
+        if(nodess[i].className==='panoSelect'){
+            nodess[i].className = 'pano'
+            let pano_select = -1
+            if(is_right){
+                pano_select = i===nodess.length -1? 0:i+1
+            }else{
+                pano_select = i===0? nodess.length -1:i-1
+            }
+            house.idx = pano_select
+            nodess[pano_select].className='panoSelect'
+            // update conver
+            const conver = document.getElementById('cover')
+            // conver.src='./panos/'+house.src[pano_select].name +"4k_f.jpg"
+            conver.setAttribute('data-id',pano_select)
+
+            // const descriptTitle=document.getElementById("descriptTitle");
+            // descriptTitle.innerHTML = house.src[house.idx].title
+
+            // const descriptContent=document.getElementById("descriptContent");
+            // descriptContent.innerHTML = house.src[house.idx].descript
+            const offset = document.getElementsByClassName("thumb")
+            const offset_width = offset.length>1&&offset[1].clientWidth?offset[1].clientWidth:180
+            // document.getElementById('listContent').scrollLeft =offset_width*pano_select;
+            const fromLeft = document.getElementById('listContent').scrollLeft
+            const toLeft = offset_width*pano_select
+            const coords = {x: fromLeft, y: 0} // Start at (0, 0)
+            const tween = new TWEEN.Tween(coords) // Create a new tween that modifies 'coords'.
+                .to({x: toLeft, y: 200}, 1000) // Move to (300, 200) in 1 second.
+                .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
+                .onUpdate(() => {
+                    // Called after tween.js updates 'coords'.
+                    // Move 'box' to the position described by 'coords' with a CSS translation.
+                    document.getElementById('listContent').scrollLeft = coords.x
+                })
+                .start() // Start the tween immediately.
+    
+
+
+            i = nodess.length
+
+            is_yuyue = false
+        } 
+    } 
+
+    console.log('is_yuyue',is_yuyue)
+
+    if(is_yuyue === true){
+
+        if(is_right){
+            document.getElementById('play').style.backgroundImage='url("./nanimages/play4.png")'
+            document.getElementById('ybf_yuyue').style.backgroundImage='url("./nanimages/yykf2_sel.png")'
+            house.select_status = 1
+        }else{
+            document.getElementById('play').style.backgroundImage='url("./nanimages/play_click.png")'
+            document.getElementById('ybf_yuyue').style.backgroundImage='url("./nanimages/yykf2_non.png")'
+        }
+    }
+}
+
+function enterPano(){
+
+    console.log('dsddddddddddd')
+
+    if(house.select_status==0){
+        const conver = document.getElementById('cover')
+
+        const panoId = conver.getAttribute('data-id')
+        const backurl = conver.getAttribute('data-backurl')
+
+
+        const url = "tip.html?id="+panoId + '&backurl='+backurl
+
+        console.log('url',url)
+        //  window.location.replace(url)  
+
+        Quit()
+
+        window.location.href = url 
+
+        //  Var param = “{"vrUrl":"http://112.18.251.84:8090/tv/h5v2/activity2/vtour/tour.html"}”
+        // const param = '{"vrUrl":"http://112.18.251.84:8090/tv/h5v2/activity2/vtour/tour.html"}'
+
+        // UtilToJS.startVrBrowser(param);
+    }else{
+
+        
+        startYuYue()
+    }
+
+
+}
+
+
+
+function startYuYue(){
+    const is_sel = document.getElementById('yuyue_ok').getAttribute('data-sel');
+
+    switch(house.yy_step){
+        case 0:
+            house.yy_step++
+
+            house.is_yuyue = true
+            document.getElementById("kanfang_yuding").style.display='flex'
+            document.getElementById("yd_phone").style.display = 'flex'
+            document.getElementById('yd_phone').focus();
+            break
+        case 1:
+            
+            if(is_sel=='true'){
+
+                const phone = document.getElementById('yd_phone').value
+                if(phone.length==0){
+                    house.yy_step = 0
+                    document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+                    document.getElementById("kanfang_yuding").style.display='none'
+                    document.getElementById("yd_phone").style.display = 'flex'
+                    document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+                    document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+                    house.is_yuyue = false
+                }else{
+                    house.yy_step++
+                    document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yy_success.png)";
+                    document.getElementById("yd_phone").style.display = 'none'
+                }
+            }
+
+            break
+        case 2:
+            
+            if(is_sel=='true'){
+                house.yy_step = 0
+                document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+                document.getElementById("kanfang_yuding").style.display='none'
+                document.getElementById("yd_phone").style.display = 'flex'
+                document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+                document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+                // document.getElementById('yd_phone').focus();
+                house.is_yuyue = false
+            }
+
+            break
+    }
+}
+
+
+// function onKeyUp(e){
+//     switch(e.keyCode){
+//         case 38://ArrowUp
+//             selectUpnDown(false)
+//             break
+//         case 40://ArrowDown
+//             selectUpnDown(true)
+//             break
+//         case 37: //ArrowLeft
+//             selectLeftnRight(false)
+//             break
+//         case 39://ArrowRight
+//             selectLeftnRight(true)
+//             break
+//         case 13://Enter
+            
+//         case 48: // auto play
+//             break
+//         case 49:
+//             break
+//         default:
+//             break
+//     }
+// }
+
+
+animate()
+
+function animate() {
+	requestAnimationFrame(animate)
+
+	TWEEN.update()
+
+}
+
+
+var btn = new tvSysBtnBind({
+    id: "Jdoc",
+    className: "ctrlBtn",
+    currentClass: "current",
+    keyRemoveDefault: false,
+    effect: "base",
+    currentIndex: 0,
+    onLoad: function(e) {
+
+    },
+    onPress:function() {
+        var keyCode = this.event.keyCode;
+        // alert('tvSysBtnBind:'+keyCode+" - " + this.event.key)
+        switch (keyCode) {
+            case 37: // left
+            // reloadData();
+            selectLeftnRight(false)
+            break;
+            case 39: // right
+            selectLeftnRight(true)
+            break;
+            case 38: //up
+            selectUpnDown(false)
+            break;
+            case 40: //down
+            selectUpnDown(true)
+            break;
+            // case 13: //enter
+            
+            // break;
+            case 33: //chanel +
+            
+            break;
+            case 34: //chanel -
+            
+            break;
+            case 48: //0
+            
+            break;
+            default:
+                break;
+        }
+    },
+    onEnterPress: function() {
+        enterPano()
+    },
+    onBack: function() {
+    //    enterPano()       
+        // window.location.replace(backurl) 
+        // window.location.href = url 
+        console.log(house.is_yuyue)
+        if(!house.is_yuyue){
+            // const backurl = house.backurl
+
+            // window.location.href = backurl 
+            const conver = document.getElementById('cover')
+            const backurl = conver.getAttribute('data-backurl')
+            console.log('backurl',backurl)
+
+            Quit()
+
+            const url = 'pano3.html?backurl='+backurl
+
+            window.location.href = url
+            
+        }else{
+
+            console.log('house.yy_step',house.yy_step)
+
+            // document.getElementById('debug').innerHTML +="<br>" +'house.yy_step'+house.yy_step
+            if(house.yy_step==1){
+                const phone = document.getElementById('yd_phone').value
+                const qy_phone = phone.length>1?phone.substring(0,phone.length-1):''
+                document.getElementById('yd_phone').value = qy_phone
+            }else{
+
+            }
+        }
+    }
+});
+
+
+window.onBackEvent= function(){
+    // document.getElementById('debug').innerHTML +="<br>" +'window.onBackEvent'
+    if(!house.is_yuyue){
+        const conver = document.getElementById('cover')
+        const backurl = conver.getAttribute('data-backurl')
+        console.log('backurl',backurl)
+
+        Quit()
+
+        const url = 'pano3.html?backurl='+backurl
+
+        // document.getElementById('debug').innerHTML +="<br>" +url
+
+        window.location.href = url
+    }else{
+        house.yy_step = 0
+        document.getElementById("kanfang_yuding").style.backgroundImage = "url(./nanimages/tc_yuyue.png)";
+        document.getElementById("kanfang_yuding").style.display='none'
+        document.getElementById("yd_phone").style.display = 'flex'
+        document.getElementById('yuyue_ok').src ='./nanimages/qd_non.png';
+        document.getElementById('yuyue_ok').setAttribute('data-sel',false);
+        // document.getElementById('yd_phone').focus();
+        house.is_yuyue = false
+
+
+    }
+
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 1
smty/js/ybf.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/bingmaps.js


BIN
smty/lib/plugins/bingmaps.swf


+ 522 - 0
smty/lib/plugins/combobox.xml

@@ -0,0 +1,522 @@
+<krpano>
+
+	<!--
+		krpano 1.20.9 combobox.xml Plugin
+		https://krpano.com/plugins/combobox/
+
+		- This plugin converts <combobox> elements in the current xml
+		  into <layer> container, scrollarea and textfield elements.
+		- Additionally it's also possible to add and remove combobox
+		  elements also dynamically.
+		- The full xml implementation allows many ways of customizing
+		  for own needs - custom designs/styles, custom functionality.
+		- The plugin works automatically the same for HTML5 and Flash.
+		- It's possible to use this plugin as replacement for the old
+		  combobox.swf/combobox.js plugins, the action interfaces are
+		  the same.
+
+
+		Syntax for Static XML Code:
+
+			<combobox name="..." design="..." ...any layer settings...>
+				<item name="..." caption="..." onclick="..." />
+				<item name="..." caption="..." onclick="..." />
+			</combobox>
+
+		Syntax for Dynamic XML Code:
+
+		 - Global Actions:
+
+			addComboboxLayer(cbname, design*)
+			removeComboboxLayer(cbname);
+
+		 - Combobox Layer Actions:
+
+			layer[cbname].addItem(caption, onclick)
+			layer[cbname].addNamedItem(name, caption, onclick)
+			layer[cbname].addIdItem(name, caption, onclick);       same as addNamedItem (for combobox.js compatibility)
+			layer[cbname].selectItem(caption)
+			layer[cbname].selectItemByName(name_or_index)
+			layer[cbname].selectIdItem(name_or_index)              same as selectItemByName (for combobox.js compatibility)
+			layer[cbname].removeAll()
+			layer[cbname].openList()
+			layer[cbname].closeList()
+
+		 - Events/Callbacks:
+
+			layer[cbname].onChange
+
+		- Combobox Layer Attributes:
+
+			layer[cbname].item              - krpano Array of the items
+			layer[cbname].selecteditemindex - current selected item index
+	-->
+
+	<!-- path to the scrollarea plugin -->
+	<combobox_scrollareaplugin
+		url.html5="%VIEWER%/plugins/scrollarea.js"
+		url.flash="%VIEWER%/plugins/scrollarea.swf"
+		/>
+
+	<!-- core internal layer styles -->
+	<style name="combobox_container_style" type="container" maskchildren="true" bgcapture="true" visible="false" onclick="combobox_onclick_event();" mergedalpha="false" alpha="1.0" />
+	<style name="combobox_marker_style" type="text" align="righttop" edge="center" html="▼" havemarkersize="false" onautosized="set(havemarkersize,true);" mergedalpha="false" alpha="1.0" />
+	<style name="combobox_item_style" type="text" wordwrap="false" vcenter="true" align="lefttop" onover="if(!combbox_item_pressed,onoveritem());asyncloop(hovering,,if(!combbox_item_pressed,onoutitem()));" ondown="onoveritem(); set(combbox_item_pressed,true);" onup="onoutitem(); set(combbox_item_pressed,false);" onoveritem="set(bg,true);" onoutitem="set(bg,false);" mergedalpha="false" alpha="1.0" />
+
+	<!-- several pre-defined designs -->
+	<combobox_design name="default" margin="2" open_close_speed="0.25">
+		<!-- default design - white box with black text and blue selection -->
+		<style name="combobox_container_style" bgalpha="1.0" bgcolor="0xFFFFFF" bgborder="1 0xFFFFFF 0.5" bgroundedge="1" bgshadow="0 1 3 0x000000 1.0" />
+		<style name="combobox_marker_style" css="color:#FFFFFF;" bg="false" txtshadow="0 0 2 0x000000 1" />
+		<style name="combobox_item_style" css="color:#222222;" padding="4 4" bg="false" bgcolor="0xC7E4FC" bgalpha="1.0" bgroundedge="1" txtshadow="0 0 1 0xFFFFFF 1.0" />
+	</combobox_design>
+
+	<combobox_design name="vtour" margin="4" open_close_speed="0.25">
+		<!-- default vtourskin.xml design -->
+		<style name="combobox_container_style" bgalpha="0.8" bgcolor="0x2D3E50" bgborder="0" bgroundedge="1" bgshadow="0 4 10 0x000000 0.3" />
+		<style name="combobox_marker_style" css="color:#FFFFFF;" bg="false" txtshadow="0 0 2 0x000000 1" />
+		<style name="combobox_item_style" css="color:#FFFFFF;" padding="4 4" bg="false" bgcolor="0xFFFFFF" bgalpha="0.5" bgroundedge="0" txtshadow="0 0 2 0x000000 1" />
+	</combobox_design>
+
+
+	
+	
+
+	<!-- internal events -->
+	<events name="combobox_xml_plugin_events" keep="true"
+	        onresize="combobox_closelist();"
+	        />
+
+	<!-- krpano version check -->
+	<action name="combobox_versioncheck" autorun="preinit">
+		if(build LT '2020-11-01',
+			error('combobox.xml - too old krpano version!');
+			set(events[combobox_xml_plugin_events].name, null);
+			set(action[addComboboxLayer].content, '');
+			set(action[removeComboboxLayer].content, '');
+		  ,
+			combobox_xml_init();
+		);
+	</action>
+
+	<action name="combobox_xml_init">
+		<!-- set auto call again on next xml load -->
+		set(action[combobox_xml_init].autorun, onload);
+		
+		combobox_parse_xml_elements();
+	</action>
+	
+
+	<!-- convert all <combobox> elements to layers -->
+	<action name="combobox_parse_xml_elements" scope="localonly">
+		if(global.combobox,
+			copy(combobox_src, global.combobox);
+			delete(global.combobox);
+			def(i, integer, 0);
+			def(cnt, integer, get(combobox_src.count));
+			if(cnt GT 0, loop(i LT cnt,
+				copy(cb, combobox_src[get(i)]);
+				if(cb AND cb.name AND cb.parsed != true,
+					set(cb.parsed, true);
+					addComboboxLayer(get(cb.name), get(cb.design));
+					copy(ly, global.layer[get(cb.name)]);
+					copyattributes(get(ly), get(cb));
+					set(ly.keep, true);
+					def(item_cnt, integer, get(cb.item.count));
+					if(item_cnt GT 0,
+						def(item_i, integer, 0);
+						loop(item_i LT  item_cnt,
+							combobox_additem(get(ly.name), get(cb.item[get(item_i)].name), get(cb.item[get(item_i)].caption), get(cb.item[get(item_i)].onclick), get(cb.item[get(item_i)].oninit));
+							inc(item_i);
+						);
+					);
+				);
+				inc(i);
+			));
+		);
+	</action>
+
+
+	<!-- dynamically add a combobox layer -->
+	<action name="addComboboxLayer" scope="localonly" args="cbname, design">
+		<!-- create the layer -->
+		addlayer(get(cbname));
+		copy(cb, global.layer[get(cbname)]);
+		set(cb.keep, true);
+		
+		<!-- copy the design settings (or set defaults) -->
+		if(!global.combobox_design[get(design)].name, set(design,'default'));
+		copy(cb.cbdesign, global.combobox_design[get(design)]);
+		calc(cb.margin, cb.cbdesign.margin !== null ? cb.cbdesign.margin : 2);
+		calc(cb.open_close_speed, cb.cbdesign.open_close_speed !== null ? cb.cbdesign.open_close_speed : 0.25);
+		<!-- load the styles and copy the design style settings -->
+		cb.loadstyle(combobox_container_style);
+		copyattributes(get(cb), get(cb.cbdesign.style[combobox_container_style]));
+
+		<!-- add/build/map actions -->
+		calc(cb.addItem,          'combobox_additem(' + cbname + ', null, "%%1", "%%2");');
+		calc(cb.addNamedItem,     'combobox_additem(' + cbname + ', "%%1", "%%2", "%%3");');
+		calc(cb.addIdItem,        'combobox_additem(' + cbname + ', "%%1", "%%2", "%%3");');
+		calc(cb.selectItem,       'combobox_finditem(' + cbname + ', "%%1", __cb_fi); if(__cb_fi GE 0, combobox_selectitem(' + cbname + ', get(__cb_fi))); delete(__cb_fi);');
+		calc(cb.selectItemByName, 'combobox_selectitem(' + cbname + ', "%%1");');
+		calc(cb.selectIdItem,     'combobox_selectitem(' + cbname + ', "%%1");');
+		calc(cb.removeAll,        'combobox_removeitems(' + cbname + ');');
+		calc(cb.openList,         'combobox_openlist(' + cbname + ');');
+		calc(cb.closeList,        'combobox_closelist(' + cbname + ');');
+
+		<!-- create sub-layers -->
+		calc(saname, 'combobox_' + cbname + '_scrollarea');
+		addlayer(get(saname));
+		copy(sa, global.layer[get(saname)]);
+		copy(sa.parent, cbname);
+		copy(sa.url, global.combobox_scrollareaplugin.url);
+		copy(sa.keep, true);
+		copy(sa.align, lefttop);
+		set(sa.direction, v);
+		set(sa.enabled, false);
+		set(sa.width, 100%);
+		set(sa.height, 100%);
+		copy(cb.scrollarea, sa);
+
+		calc(mkname, 'combobox_' + cbname + '_marker');
+		addlayer(get(mkname));
+		copy(mk, global.layer[get(mkname)]);
+		copy(mk.parent, saname);
+		copy(mk.keep, true);
+		mk.loadstyle(combobox_marker_style);
+		copyattributes(get(mk), get(cb.cbdesign.style[combobox_marker_style]));
+		copy(cb.marker, mk);
+
+		<!-- item data array -->
+		cb.createarray('item');
+
+		<!-- item autosizing information -->
+		set(cb.autosize_i, 0);
+		set(cb.autosize_cnt, 0);
+		set(cb.autosize_max_w, 0);
+		set(cb.autosize_max_h, 0);
+
+		set(cb.lastselecteditemindex, 0);
+		set(cb.selecteditemindex, 0);
+	</action>
+
+
+	<!-- dynamically remove a combobox element -->
+	<action name="removeComboboxLayer" scope="localonly" args="cbname">
+		if(global.layer[get(cbname)],
+			copy(cb, global.layer[get(cbname)]);
+			if(cb === global.openedcombobox, delete(global.openedcombobox));
+			if(cb,
+				removelayer(get(cbname), true);
+			);
+		);
+	</action>
+
+
+	<!-- default onclick event for combobox elements: open the list -->
+	<action name="combobox_onclick_event">
+		combobox_openlist(get(name));
+	</action>
+
+
+	<!-- dynamically add items -->
+	<action name="combobox_additem" scope="localonly" args="cbname, itemname, itemcaption, itemonclick, itemoninit">
+		copy(cb, global.layer[get(cbname)]);
+		
+		<!-- when no item name is set, generate an automatic one -->
+		if(itemname === null, calc(itemname, 'autoname_' + cb.item.count); );
+		
+		<!-- save the item caption and onclick event -->
+		copy(cb.item[get(itemname)].caption, itemcaption);
+		copy(cb.item[get(itemname)].onclick, itemonclick);
+
+		inc(cb.autosize_cnt);
+
+		<!-- create the item layer/textfield -->
+		calc(itemlayername, 'comboboxitem_' + cbname + '_' + itemname);
+		addlayer(get(itemlayername));
+		copy(li, global.layer[get(itemlayername)]);
+		li.loadstyle(combobox_item_style);
+		copyattributes(get(li), get(cb.cbdesign.style[combobox_item_style]));
+		copy(li.parent, cb.scrollarea.name);
+		copy(li.keep, true);
+		copy(li.cblayername, cb.name);
+		copy(li.itemname, itemname);
+		copy(li.html, itemcaption);
+		set(li.onautosized, delayedcall(0,combobox_item_autosize_update()) );
+		set(li.onclick, combobox_item_onclick() );
+		if (isset(itemoninit), callwith(li, itemoninit));
+
+		copy(cb.item[get(itemname)].itemlayername, itemlayername);
+		copy(cb.item[get(itemname)].itemlayer, li);
+	</action>
+
+
+	<!-- onautosized callback from the item textfield -->
+	<action name="combobox_item_autosize_update" scope="localonly">
+		copy(cb, global.layer[get(caller.cblayername)]);
+		inc(cb.autosize_i);
+		Math.max(cb.autosize_max_w, caller.width);
+		Math.max(cb.autosize_max_h, caller.height);
+		if(cb.autosize_i == cb.autosize_cnt, combobox_align_items(get(cb.name)); );
+	</action>
+
+
+	<!-- align the image and set the combobox size -->
+	<action name="combobox_align_items" scope="localonly" args="cbname">
+		copy(cb, global.layer[get(cbname)]);
+		if(cb.marker.havemarkersize == false OR cb.scrollarea.loaded == false,
+			<!-- wait until everything is ready -->
+			delayedcall(calc(cb.name + '_waitformarkersize'), 0.01, combobox_align_items(get(cbname)) );
+		  ,
+			<!-- set the item positions and the combobox size -->
+			if(global.openedcombobox === cb, combobox_closelist() );
+			copy(sa, cb.scrollarea);
+			calc(itemwidth, cb.margin GT 0 ? -2 * cb.margin : '100%');
+			copy(mk_w, cb.marker.width);
+			copy(item_cnt, cb.autosize_cnt);
+
+			for(def(item_i, integer, 0), item_i LT item_cnt, inc(item_i),
+				copy(li, global.layer[get(cb.item[get(item_i)].itemlayername)]);
+				set(li.x, get(cb.margin));
+				copy(li.width, itemwidth);
+				copy(li.height, cb.autosize_max_h);
+				calc(li.y, cb.margin + item_i * (cb.autosize_max_h + cb.margin));
+			);
+
+			if(cb.width == null OR cb.width == cb.lastautosizedwidth,
+				<!-- no combobox width (or an autosized width) set - set the largest item width -->
+				calc(cb.width, cb.margin + cb.autosize_max_w + 2 + mk_w + cb.margin);
+				copy(cb.lastautosizedwidth, cb.width);
+			);
+
+			calc(cb.height, 2*cb.margin + cb.autosize_max_h);
+			calc(sa.height, cb.margin + item_cnt*(cb.margin+cb.autosize_max_h));
+			calc(sa.y, -(cb.selecteditemindex * (cb.autosize_max_h + cb.margin)));
+			calc(cb.marker.x, cb.margin + mk_w/2);
+			tween(global.layer[get(cb.name)].marker.y, calc(cb.margin + cb.selecteditemindex*(cb.autosize_max_h + cb.margin) + cb.autosize_max_h/2), 0.1);
+
+			<!-- when all is done, show the combobox -->
+			delayedcall(0.1, set(global.layer[get(cb.name)].visible,true); );
+		);
+	</action>
+
+
+	<!-- helper action for calling a plugin event-code with 'global' and 'caller' scope -->
+	<action name="combobox_do_event_call" scope="local" args="cb, eventcode">
+		if(eventcode !== null, callwith(cb, get(eventcode) ); );
+	</action>
+	
+
+	<!-- default onclick event for items: select the current item, close the list and call the item onclick event -->
+	<action name="combobox_item_onclick" scope="localonly">
+		copy(cb, global.layer[get(caller.cblayername)]);
+		copy(itemname, caller.itemname);
+		combobox_selectitem(get(cb.name), get(itemname));
+
+		if(global.openedcombobox === cb, combobox_closelist() );
+
+		if(cb.item[get(itemname)].onclick,
+			if(cb.callonclickafterclose === false,
+				<!-- call instantly -->
+				combobox_do_event_call(get(cb), get(cb.item[get(itemname)].onclick));
+			  ,
+				<!-- call the onclick event after the combobox has closed -->
+				delayedcall(get(cb.open_close_speed),
+					copy(cb.curitem, cb.item[get(itemname)]);
+					combobox_do_event_call(get(cb), get(cb.item[get(itemname)].onclick));
+				);
+			);
+		);
+	</action>
+
+
+	<!-- select an item -->
+	<action name="combobox_selectitem" scope="localonly" args="cbname, itemname">
+		if(global.combbox_item_pressed != true,
+			copy(cb, global.layer[get(cbname)]);
+			copy(cb.lastselecteditemindex, cb.selecteditemindex);
+			copy(cb.selecteditemindex, cb.item[get(itemname)].index);
+			<!-- call onchange event on selection change -->
+			if(cb.lastselecteditemindex != cb.selecteditemindex AND cb.onchange,
+				combobox_do_event_call(get(cb), get(cb.onchange));
+			);
+			if(global.openedcombobox === cb,
+				<!-- when opened, just close to the selected item -->
+				combobox_closelist();
+			  ,
+				if(global.layer[get(cbname)].scrollarea.loaded,
+					global.layer[get(cbname)].scrollarea.stopscrolling();
+					calc(offset, cb.selecteditemindex*(cb.autosize_max_h + cb.margin));
+					tween(global.layer[get(cbname)].marker.y, calc(cb.margin + offset + cb.autosize_max_h/2), 0);
+					tween(global.layer[get(cbname)].scrollarea.y, calc(-offset), 0, default, global.layer[get(cbname)].scrollarea.update(); );
+				);
+			);
+		);
+	</action>
+
+
+	<!-- find an item by its caption, the global variable defined in 'returnvariable' will contain the index  -->
+	<action name="combobox_finditem" scope="localonly" args="cbname, itemcaption, returnvariable">
+		copy(cb, global.layer[get(cbname)]);
+		copy(item_cnt, cb.item.count);
+		set(calc('global.' + returnvariable), -1);
+		for(def(item_i, integer, 0), item_i LT  item_cnt, inc(item_i),
+			if(cb.item[get(item_i)].caption == itemcaption,
+				copy(calc('global.' + returnvariable), item_i);
+				copy(item_i, item_cnt);
+			);
+		);
+	</action>
+
+
+	<!-- remove all items (to be able to add new ones) -->
+	<action name="combobox_removeitems" scope="localonly" args="cbname">
+		copy(cb, global.layer[get(cbname)]);
+		if(global.openedcombobox === cb, combobox_closelist() );
+
+		<!-- remove all item layers -->
+		calc(item_i, cb.item.count - 1);
+		loop(item_i GE 0,
+			removelayer(get(cb.item[get(item_i)].itemlayername));
+			dec(item_i);
+		);
+
+		<!-- reset the item information -->
+		set(cb.item.count, 0);
+		set(cb.autosize_i,0);
+		set(cb.autosize_cnt, 0);
+		set(cb.autosize_max_w, 0);
+		set(cb.autosize_max_h, 0);
+		set(cb.selecteditemindex, 0);
+		set(cb.lastselecteditemindex, 0);
+		if(cb.width == cb.lastautosizedwidth, set(cb.width, null));
+	</action>
+
+
+	<!-- open the combobox list -->
+	<action name="combobox_openlist" scope="localonly" args="cbname">
+		<!-- if another combobox is already open, close that one first -->
+		if(global.openedcombobox !== null, combobox_closelist() );
+
+		copy(cb, global.layer[get(cbname)]);
+		copy(global.openedcombobox, cb);
+		
+		<!-- move to top -->
+		copy(cb.backupzorder, cb.zorder);
+		set(cb.zorder, 999);
+
+		<!-- find the available screen space above or below the combobox -->
+		calc(cbheight, 2*cb.margin + cb.autosize_max_h);
+		set(lx1, 0);
+		set(ly1, 0);
+		copy(lx2, cb.pixelwidth);
+		copy(ly2, cbheight);
+		layertoscreen(get(cbname), lx1,ly1, lx1,ly1);
+		layertoscreen(get(cbname), lx2,ly2, lx2,ly2);
+		calc(space_above, ly1 - global.area.pixely);
+		calc(space_below, global.area.pixelheight - (ly2 - global.area.pixely));
+
+		<!-- the required space for full opening: -->
+		calc(openheight, cb.margin + cb.autosize_cnt*(cb.margin+cb.autosize_max_h) );
+
+		<!-- vertical centered alignment? -->
+		calc(cb_edge, cb.edge ? cb.edge : cb.align);
+		calc(iscentered, cb_edge == 'left' OR cb_edge == 'center' OR cb_edge == 'right');
+		if(iscentered,
+			calc(openheight_max, space_above + space_below);
+		  ,
+			Math.max(openheight_max, space_above, space_below);
+		);
+
+		<!-- limit the height to the available space (minus some margin) -->
+		Math.min(openheight, calc(openheight_max + cbheight - 20));
+
+		<!-- need vertical offset? (depending on the available space and the align/edge setting) -->
+		set(yoffset, null);
+		calc(top_overflow, -ly1 + global.area.pixely + openheight/2);
+		calc(bottom_overflow, ly2 - global.area.pixely + openheight/2 - global.area.pixelheight);
+		if(cb.parent,
+			<!-- no vertical offset inside other layers, do only a height clipping -->
+			Math.max(max_overflow, top_overflow, bottom_overflow, 0);
+			sub(openheight, max_overflow);
+		  ,
+			if(iscentered,
+				if(openheight GE (global.area.pixelheight - 20),
+					set(yoffset,0);
+				  ,
+					if(top_overflow GT 0, calc(yoffset, cb.y + top_overflow); );
+					if(bottom_overflow GT 0, calc(yoffset, cb.y - bottom_overflow); );
+				);
+			,
+				indexoftxt(isbottomalign, get(cb_edge), 'bottom');
+				if(space_above GT space_below,
+					if(isbottomalign LT 0, calc(yoffset, cb.y - openheight + cbheight); );
+				  ,
+					if(isbottomalign GE 0, calc(yoffset, cb.y - openheight + cbheight); );
+				);
+			);
+		);
+		if(yoffset != null,
+			copy(cb.ybackup, cb.y);
+			tween(global.layer[get(cbname)].y, calc(yoffset), get(cb.open_close_speed));
+		);
+
+		<!-- center the opened list at the selected item -->
+		calc(centeritem_y, -1 * (cb.margin + cb.selecteditemindex*(cb.margin+cb.autosize_max_h) + cb.autosize_max_h/2 - openheight/2));
+		clamp(centeritem_y, calc(openheight - cb.scrollarea.height), 0);
+
+		<!-- apply the changes now -->
+		tween(global.layer[get(cbname)].height, get(openheight), get(cb.open_close_speed));
+		tween(global.layer[get(cbname)].scrollarea.y, get(centeritem_y), get(cb.open_close_speed), default, global.layer[get(cbname)].scrollarea.update(); );
+
+		<!-- special html5/flash case:
+			 rotating textfields (the marker symbol here) are not possible in
+			 flash (a flashplayer limitation), so use a rotated symbol instead.
+		-->
+		if(global.device.html5,
+			tween(global.layer[get(cbname)].marker.rotate, 90, get(cb.open_close_speed));
+		  ,
+			set(global.layer[get(cbname)].marker.html, '◀');
+		);
+
+		<!-- enable the scrollarea to allow the user to drag it -->
+		set(cb.scrollarea.enabled, true);
+
+		<!-- install a global onmousedown event to close the list when clicking at the pano -->
+		set(global.events[combobox_xml_plugin_events].onmousedown, combobox_closelist() );
+	</action>
+
+
+	<!-- close the current open list -->
+	<action name="combobox_closelist" scope="localonly">
+		if(global.openedcombobox !== null,
+			copy(cb, global.openedcombobox);
+			delete(global.openedcombobox);
+			
+			<!-- restore zorder -->
+			copy(cb.zorder, cb.backupzorder);
+			
+			<!-- clear the global onmousedown event -->
+			set(global.events[combobox_xml_plugin_events].onmousedown, null);
+
+			<!-- disable the dragging -->
+			set(cb.scrollarea.enabled, false);
+
+			<!-- closing animations -->
+			calc(offset, cb.selecteditemindex*(cb.autosize_max_h + cb.margin));
+			if(cb.ybackup !== null, tween(cb.y, get(cb.ybackup), get(cb.open_close_speed)));
+			global.layer[get(cb.name)].scrollarea.stopscrolling();
+			tween(global.layer[get(cb.name)].height, calc(2*cb.margin + cb.autosize_max_h), get(cb.open_close_speed));
+			tween(global.layer[get(cb.name)].scrollarea.y, calc(-offset), get(cb.open_close_speed), default, global.layer[get(cb.name)].scrollarea.update(); );
+			tween(global.layer[get(cb.name)].marker.y, calc(cb.margin + offset + cb.autosize_max_h/2), get(cb.open_close_speed));
+			<!-- special html5/flash case: rotate marker or change symbol -->
+			if(global.device.html5,
+				tween(global.layer[get(cb.name)].marker.rotate, 0, get(cb.open_close_speed));
+			  ,
+				set(global.layer[get(cb.name)].marker.html, '▼');
+			);
+		);
+	</action>
+
+</krpano>

+ 48 - 0
smty/lib/plugins/doubleclick_style.xml

@@ -0,0 +1,48 @@
+<krpano>
+	
+	<!--
+		doubleclick_style.xml
+		krpano 1.20
+	
+		A helper style for single/double click detection for layer and hotspot elements.
+		
+		Example:
+		
+		<layer ...
+		       style="doubleclick"
+		       onsingleclick="trace('-single click-');"
+		       ondoubleclick="trace('-double click-');"
+		       />
+	-->
+	
+	<style name="doubleclick"
+	       downx="0"
+	       downy="0"
+	       clicks="0"
+	       onsingleclick=""
+	       ondoubleclick=""
+	       onclick="doubleclick_style_onclick();"
+	       />
+
+	<action name="doubleclick_style_onclick">
+	    inc(clicks);
+	    if(clicks == 2,
+	        set(clicks,0); 
+	        stopdelayedcall(doubleclickdetector);
+	        if((((mouse.x-downx)^2 + (mouse.y-downy)^2)^0.5) LT (device.touch ? 10 : 2),
+	            ondoubleclick();
+	          ,
+	            onsingleclick();
+	            onsingleclick();
+	        );
+	      ,
+	        copy(downx, mouse.x); 
+	        copy(downy, mouse.y);
+	        delayedcall(doubleclickdetector, 0.3, 
+	            set(clicks,0); 
+	            onsingleclick();
+	        );
+	    );
+	</action>
+	
+</krpano>

+ 28 - 0
smty/lib/plugins/fps.xml

@@ -0,0 +1,28 @@
+<krpano>
+
+	<!--
+		fps (frames per second) xml plugin
+		- this plugin shows the current average rendering frame-rate
+	-->
+
+	<action name="fps_install" autorun="preinit" scope="local">
+		delayedcall(0.5,
+			addlayer(fps_display);
+			set(layer[fps_display],
+				type=text,
+				keep=true,
+				align='lefttop',
+				css=calc('font-size:'+(device.mobile AND stagescale LT 1.0 ? 24 : 12)+'px; color:#FFFFFF;'),
+				txtshadow='0 0 1 0x000000 1.0',
+				bg=false,
+				parent=STAGE,
+				vr=true,
+				enabled=false
+			);
+			setinterval(fps_plugin, 0.5,
+				calc(layer[fps_display].html, 'FPS: ' + ((display.currentfps+0.5) BOR 0));
+			);
+		);
+	</action>
+
+</krpano>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/googlemaps.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/gyro2.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/pp_blur.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/pp_light.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/pp_sharpen.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 19 - 0
smty/lib/plugins/scrollarea.js


BIN
smty/lib/plugins/scrollarea.swf


+ 214 - 0
smty/lib/plugins/showtext.xml

@@ -0,0 +1,214 @@
+<krpano>
+	<!--
+		showtext() xml plugin
+		- showtext() and <textstyle> support for HTML5
+		- extended <textstyle> functionality compared to the build-in showtext() action
+		- just include this xml file via: <include url="showtext.xml" />
+		- docu: https://krpano.com/plugins/showtext/
+		- krpano 1.20
+	-->
+
+
+	<!-- predefine a DEFAULT textstyle element -->
+	<textstyle name="DEFAULT" />
+	
+	
+
+
+	<!-- the automatic running (autorun=preinit) install action -->
+	<action name="showtext_install" autorun="preinit" scope="private:showtext">
+		<!-- remove the build-in 'showtext' function to use the 'showtext' <action> instead: -->
+		delete(global.showtext);
+
+		<!-- initialize internal variables -->
+		set(showtext_style, DEFAULT);
+		set(showtext_prevstyle, null);
+		set(showtext_text, '');
+		set(showtext_prevtext, '');
+		set(showtext_timeout, 0.1);
+		set(showtext_fadeout, 0.0);
+		set(showtext_clipping, false);
+	</action>
+	
+
+	<action name="showtext" scope="private:showtext" args="text, style">
+		if(!style, set(style, DEFAULT));
+		
+		if(global.textstyle[get(style)], 
+			copy(showtext_style, style);
+		  ,
+			warning("showtext() - there is no textstyle '", style, "' defined!");
+			global.textstyle.createarrayitem(get(style));
+		);
+
+		copy(showtext_text, text);
+		
+		if(showtext_text != showtext_prevtext,
+			copy(showtext_prevtext, showtext_text);
+			showtext_createnewtext();
+		  ,
+			delayedcall(showtext_timer, get(showtext_timeout), showtext_hide() );
+		  );
+	</action>
+	
+
+	<action name="showtext_createnewtext" scope="private:showtext">
+		<!-- stop running mouse and alpha update calls -->
+		stopdelayedcall(showtext_mouseupdates);
+		stoptween(global.layer[showtext_tf].alpha);
+
+		<!-- remove the old textfield when the style has changed -->
+		if(showtext_style != showtext_prevstyle,
+			copy(showtext_prevstyle, showtext_style);
+			removelayer(showtext_tf);
+		  );
+		  
+		<!-- create a new textfield plugin layer -->
+		addlayer(showtext_tf);
+
+		<!-- create 'shortcut' variables (tf,ts) for faster access -->
+		copy(tf, global.layer[showtext_tf]);
+		copy(ts, global.textstyle[get(showtext_style)]);
+
+		<!-- get the position settings -->
+		if(ts.origin  !== null, copy(ts_origin,  ts.origin),  set(ts_origin, 'cursor'));
+		if(ts.edge    !== null, copy(ts_edge,    ts.edge),    set(ts_edge, 'bottom'));
+		if(ts.xoffset !== null, copy(ts_xoffset, ts.xoffset), set(ts_xoffset, 0));
+		if(ts.yoffset !== null, copy(ts_yoffset, ts.yoffset), set(ts_yoffset, -3));
+
+		<!-- set the position settings -->
+		if(ts_origin == 'cursor',
+			set(tf.align, 'lefttop');
+			showtext_movetomouse();
+		  ,
+			copy(tf.align, ts_origin);
+		  );
+		copy(tf.edge, ts_edge);
+		copy(tf.ox, ts_xoffset);
+		copy(tf.oy, ts_yoffset);
+
+		<!-- get the font settings -->
+		if(ts.font      !== null, copy(ts_font,      ts.font),      set(ts_font, 'Times'));
+		if(ts.fontsize  !== null, copy(ts_fontsize,  ts.fontsize),  set(ts_fontsize, 12.0));
+		if(ts.bold      !== null, copy(ts_bold,      ts.bold),      set(ts_bold, true));
+		if(ts.italic    !== null, copy(ts_italic,    ts.italic),    set(ts_italic, false));
+		if(ts.textcolor !== null, copy(ts_textcolor, ts.textcolor), set(ts_textcolor, 0x000000));
+		if(ts.textalign !== null, copy(ts_textalign, ts.textalign), set(ts_textalign, 'left'));
+
+		<!-- use the font settings to build the CSS style -->
+		set(tf_css, '');
+		tohex(ts_textcolor, '#', 6);
+		txtadd(tf_css, 'font-family:',get(ts_font),'; font-size:',get(ts_fontsize),'px; color:',get(ts_textcolor),'; ');
+		if(ts_textalign != 'none', txtadd(tf_css, get(tf_css), 'text-align:',get(ts_textalign),'; '));
+		if(ts_bold,   txtadd(tf_css, 'font-weight:bold; '));
+		if(ts_italic, txtadd(tf_css, 'font-style:italic; '));
+		if(ts.css !== null, txtadd(tf_css, get(ts.css)));
+		copy(tf.css, tf_css);
+
+		<!-- size settings -->
+		if(ts.width   !== null AND ts.width   !== '', copy(tf.width,   ts.width));
+		if(ts.height  !== null AND ts.height  !== '', copy(tf.height,  ts.height));
+		if(ts.vcenter !== null AND ts.vcenter !== '', copy(tf.vcenter, ts.vcenter));
+		if(ts.padding !== null AND ts.padding !== '', copy(tf.padding, ts.padding), set(tf.padding,1));
+
+		<!-- background, border, shadow settings -->
+		if(ts.background      !== null, copy(tf.background,      ts.background));
+		if(ts.backgroundcolor !== null, copy(tf.backgroundcolor, ts.backgroundcolor));
+		if(ts.backgroundalpha !== null, copy(tf.backgroundalpha, ts.backgroundalpha));
+		if(ts.border          !== null, copy(tf.border,          ts.border), set(tf.border,true));
+		if(ts.bordercolor     !== null, copy(tf.bordercolor,     ts.bordercolor));
+		if(ts.borderalpha     !== null, copy(tf.borderalpha,     ts.borderalpha));
+		if(ts.borderwidth     !== null, copy(tf.borderwidth,     ts.borderwidth));
+		if(ts.roundedge       !== null, copy(tf.roundedge,       ts.roundedge));
+		if(ts.shadow          !== null, copy(tf.shadow,          ts.shadow));
+		if(ts.shadowrange     !== null, copy(tf.shadowrange,     ts.shadowrange));
+		if(ts.shadowangle     !== null, copy(tf.shadowangle,     ts.shadowangle));
+		if(ts.shadowcolor     !== null, copy(tf.shadowcolor,     ts.shadowcolor));
+		if(ts.shadowalpha     !== null, copy(tf.shadowalpha,     ts.shadowalpha));
+		if(ts.textshadow      !== null, copy(tf.textshadow,      ts.textshadow));
+		if(ts.textshadowrange !== null, copy(tf.textshadowrange, ts.textshadowrange));
+		if(ts.textshadowangle !== null, copy(tf.textshadowangle, ts.textshadowangle));
+		if(ts.textshadowcolor !== null, copy(tf.textshadowcolor, ts.textshadowcolor));
+		if(ts.textshadowalpha !== null, copy(tf.textshadowalpha, ts.textshadowalpha));
+
+		<!-- showing settings -->
+		if(ts.alpha      !== null, copy(ts_alpha,      ts.alpha),      set(ts_alpha, 1.0));
+		if(ts.showtime   !== null, copy(ts_showtime,   ts.showtime),   set(ts_showtime, 0.1));
+		if(ts.fadetime   !== null, copy(ts_fadetime,   ts.fadetime),   set(ts_fadetime, 0.0));
+		if(ts.fadeintime !== null, copy(ts_fadeintime, ts.fadeintime), set(ts_fadeintime, 0.0));
+		copy(showtext_timeout, ts_showtime);
+		copy(showtext_fadeout, ts_fadetime);
+		if(ts_fadeintime GT 0,
+			set(tf.alpha, 0.0);
+			tween(global.layer[showtext_tf].alpha, get(ts_alpha), get(ts_fadeintime), linear);
+		  ,
+			copy(tf.alpha, ts_alpha);
+		  );
+
+		if(ts.noclip !== null, copy(showtext_clipping,ts.noclip), set(showtext_clipping, true));
+		
+		if(showtext_clipping,
+			set(tf.onloaded,    showtext_do_clipping() );
+			set(tf.onautosized, showtext_do_clipping() );
+		  );
+
+		<!-- special flash-only settings -->
+		if(ts.embeddedfonts !== null, copy(tf.embeddedfonts, ts.embeddedfonts));
+		if(ts.effect        !== null, copy(tf.effect,        ts.effect));
+		if(ts.blendmode     !== null, copy(tf.blendmode,     ts.blendmode));
+
+		<!-- set the text and the basic settings to start showing the textfield -->
+		copy(tf.html, showtext_text);
+		set(tf.enabled, false);
+		set(tf.zorder, 999999);
+		if(ts.parent, copy(tf.parent, ts.parent) );
+		set(tf.type, 'text');
+
+		<!-- start the text-hiding timer -->
+		delayedcall(showtext_timer, get(showtext_timeout), showtext_hide() );
+	</action>
+
+
+	<action name="showtext_do_clipping" scope="private:showtext">
+		if(showtext_clipping,
+			global.layer[showtext_tf].updatepos();
+			copy(tf_px, global.layer[showtext_tf].pixelx);
+			copy(tf_py, global.layer[showtext_tf].pixely);
+			if(tf_px LT 0,
+				sub(global.layer[showtext_tf].x, tf_px);
+			  ,
+				add(tf_rightedge, tf_px, global.layer[showtext_tf].pixelwidth);
+				if(tf_rightedge GE global.stagewidth, sub(tf_rightedge,global.stagewidth); sub(global.layer[showtext_tf].x,tf_rightedge); );
+			  );
+			if(tf_py LT 0,
+				sub(global.layer[showtext_tf].y,  tf_py);
+			  ,
+				add(tf_bottomedge, tf_py, global.layer[showtext_tf].pixelheight);
+				if(tf_bottomedge GE global.stageheight, sub(tf_bottomedge,global.stageheight); sub(global.layer[showtext_tf].y,tf_bottomedge); );
+			  );
+		  );
+	</action>
+
+
+	<action name="showtext_movetomouse" scope="private:showtext">
+		copy(global.layer[showtext_tf].x, global.mouse.stagex);
+		copy(global.layer[showtext_tf].y, global.mouse.stagey);
+
+		showtext_do_clipping();
+
+		delayedcall(showtext_mouseupdates, 0, showtext_movetomouse() );
+	</action>
+
+
+	<action name="showtext_hide" scope="private:showtext">
+		if(global.layer[showtext_tf],
+			tween(global.layer[showtext_tf].alpha, 0.0, get(showtext_fadeout), linear,
+					stopdelayedcall(showtext_mouseupdates);
+					removelayer(showtext_tf);
+					set(showtext_text, '');
+					set(showtext_prevtext, '');
+				);
+		  );
+	</action>
+
+</krpano>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/soundinterface.js


BIN
smty/lib/plugins/soundinterface.swf


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/videoplayer.js


BIN
smty/lib/plugins/videoplayer.swf


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5 - 0
smty/lib/plugins/webvr.js


+ 923 - 0
smty/lib/plugins/webvr.xml

@@ -0,0 +1,923 @@
+<krpano>
+	<!--
+		webvr.xml
+		- krpano 1.20.9
+		
+		https://krpano.com/plugins/webvr/
+	-->
+
+	<!-- load the WebVR plugin and assign it to a global 'webvr' variable -->
+	<plugin name="webvr" devices="html5" keep="true"
+	        url="webvr.js"
+	        mobilevr_support="true"
+	        mobilevr_touch_support="true"
+	        mobilevr_fake_support="true"
+	        mobilevr_profile.normal="90|60|42|0|0|0"
+	        mobilevr_profile.mobile="80|60|42|35|0.441|0.156"
+	        mobilevr_wakelock="true"
+	        fullscreen_mirroring="false"
+	        mouse_pointerlock="true"
+	        vr_cursor_onover="if(handcursor, tween(hotspot[vr_cursor].scale,0.4,0.1); vr_auto_click(get(vr_timeout)); );"
+	        vr_cursor_onout="tween(hotspot[vr_cursor].scale,0.3,0.1);"
+	        onavailable="webvr_onavailable();"
+	        onunavailable=""
+	        onunknowndevice="webvr_onunknowndevice();"
+	        onvrcontrollers="webvr_onvrcontrollers();"
+	        onentervr="webvr_onentervr();"
+	        onexitvr="webvr_onexitvr();"
+	        />
+
+
+
+	<!-- the VR cursor hotspot -->
+	<style name="vr_cursor_style" 
+		url="webvr_vrcursor.png"
+		visible="false"
+		enabled="false"
+		distorted="true"
+		crop="0|0|80|80"
+		scale="0.3"
+		depth="120"
+		/>
+	
+	<action name="webvr_load_vr_cursor_hs" scope="local">
+		addhotspot('vr_cursor', hs);
+		hs.loadstyle(vr_cursor_style);
+		set(hs.keep, true);
+		set(webvr.vr_cursor, 'hotspot[vr_cursor]');
+	</action>
+	
+	<action name="webvr_load_vr_controller_hs" scope="private:VRCONTROLLERS" args="controllerstyle">
+		removehotspot('vr_controller_l');
+		removehotspot('vr_controller_r');
+		addhotspot('vr_controller_l', vr_ctrl_l);
+		addhotspot('vr_controller_r', vr_ctrl_r);
+		set(vr_ctrl_l.keep, true);
+		set(vr_ctrl_r.keep, true);
+		vr_ctrl_l.loadstyle(calc(controllerstyle ? controllerstyle : 'vrcontroller_light_and_point'));
+		vr_ctrl_r.loadstyle(calc(controllerstyle ? controllerstyle : 'vrcontroller_light_and_point'));
+
+		<!-- optional: vibrate the controllers on hovering:
+		vr_ctrl_l.addevent('onover', pulse(1.0, 0.25) );
+		vr_ctrl_r.addevent('onover', pulse(1.0, 0.25) ); -->
+		if(!global.webvr.iswebxr,
+			vr_ctrl_l.addevent('onvrcontrollerbutton', 'if(vrbuttonindex == 3 AND vrbuttonstate == "up", vrsetup_open(); );' );
+			vr_ctrl_r.addevent('onvrcontrollerbutton', 'if(vrbuttonindex == 3 AND vrbuttonstate == "up", vrsetup_open(); );' );
+		);
+		
+		set(global.webvr.vr_controller, 'vr_controller_l,vr_controller_r');
+		set(global.have_vr_controllers, true);
+		
+		if(global.webvr.isvrbrowser AND global.webvr.vrcontrollers[0].buttons.length LE 2,
+			<!-- when there are only two buttons on the VR controller (e.g. Oculus Go) use an extra hotspot for the VR-setup -->
+			addhotspot('webvr_vrsetup', vr_setup_hs);
+			vr_setup_hs.loadstyle('webvr_button_style');
+			set(vr_setup_hs, keep=true, ath=0, atv=90, depth=160, zorder=999, torigin=view, html='VR SETUP', oversampling=3, scale=0.2, onclick='vrsetup_open();', onloaded='renderloop( copy(ath,view.hlookat); );');
+		);
+	</action>
+	
+	<action name="webvr_onvrcontrollers" scope="private:VRCONTROLLERS">
+		if(!global.have_vr_controllers, webvr_load_vr_controller_hs(); );
+	</action>
+		
+	<style name="vrcontroller_laser" 
+			url="webvr_laser.png"
+			distorted="true"
+			enabled="false"
+			visible="false"
+			width="0.5" height="1000" edge="bottom" oref="1" oy="0"
+			torigin="world" tx="0" ty="0" tz="0" depth="0"
+			zorder="99999"
+			depthbuffer="true"
+			onloaded="asyncloop(loaded, 
+				calc(height, (target AND target.hitd GT 0 ? target.hitd : 1000) / display.hotspotworldscale); 
+				);"
+			/>
+			
+	<style name="vrcontroller_light_and_point" 
+			url="webvr_light.png"
+			distorted="true"
+			enabled="false"
+			visible="false"
+			width="0.5" height="18" edge="bottom" oref="1" oy="0"
+			torigin="world" tx="0" ty="0" tz="0" depth="0"
+			zorder="99999"
+			depthbuffer="true"
+			onloaded="vrcontroller_target_point();"
+			/>
+	
+	<style name="vrcontroller_handcursor_and_point" 
+			url="webvr_handcursor.png"
+			distorted="true"
+			enabled="false"
+			visible="false"
+			width="10" height="10" edge="center" oref="1" oy="-1"
+			torigin="world" tx="0" ty="0" tz="0" depth="0"
+			zorder="99999"
+			depthbuffer="true"
+			onloaded="vrcontroller_target_point();"
+			/>
+	
+	<action name="vrcontroller_target_point" scope="localonly">
+		addhotspot(auto, hs);
+		set(hs, keep=true, type=text, bgcolor=0xFFFFFF, bgalpha=1.0, width=10, height=10, bgroundedge=5, bgborder='1 0x000000 1.0', oversampling=2,
+			scale=0.4, torigin=world, depth=0, distorted=false, zoom=true, zorder=99998, enabled=false
+		  );
+		renderloop(
+			if(!caller.loaded,
+				removehotspot(get(hs.name));
+				stoprenderloop();
+			  ,
+				if(global.display.havedepthmap,
+					<!-- use the laser for depthmap panos -->
+					removehotspot(get(hs.name));
+					stoprenderloop();
+					webvr_load_vr_controller_hs('vrcontroller_laser');
+				  ,
+					calc(hs.bgcolor, caller.pressed ? 0x049AFF : (caller.hovering ? 0x00FF00 : 0xFFFFFF));
+					calc(distance, (caller.target AND caller.target.hitd GT 0 ? caller.target.hitd : 1000));
+					calc(hs.scale, 0.4 * (distance GT 1000 ? distance / 1000 : (distance LT 200 ? 0.25 : (0.25 + (distance - 200)/800 * 0.75))));
+					calc(hs.tx, caller.tx + caller.dx * distance);
+					calc(hs.ty, caller.ty + caller.dy * distance);
+					calc(hs.tz, caller.tz + caller.dz * distance);
+				);
+			);
+		);
+	</action>
+	
+
+
+
+	<!-- vr_auto_click() - call this action in the onover event of a
+	     hotspot to trigger automatically a click after some time.  -->
+	<action name="vr_auto_click" scope="local" args="vr_aclk_timeout">
+		if(webvr.isenabled,
+			if(vr_aclk_timeout == null, set(vr_aclk_timeout, 2000));
+			copy(vr_aclk_t1, timertick);
+			set(vr_aclk_waiting, true);
+			copy(webvr.vr_aclk_hotspot, caller.name);
+			set(hotspot[vr_cursor].crop,'0|0|80|80');
+
+			asyncloop(vr_aclk_waiting AND webvr.vr_aclk_hotspot == caller.name,
+				sub(dt, timertick, vr_aclk_t1);
+
+				if(!caller.hovering,
+					set(vr_aclk_waiting, false);
+					set(hotspot[vr_cursor].crop,'0|0|80|80');
+				  ,
+					div(f, dt, vr_aclk_timeout);
+					mul(f, 16);
+					roundval(f);
+					Math.min(f, 16);
+					mul(f, 80);
+
+					txtadd(hotspot[vr_cursor].crop,get(f),'|0|80|80');
+
+					<!-- wait another 100ms delay after finishing the animation before doing the click -->
+					sub(dt, 100);
+					if(dt GT vr_aclk_timeout,
+						set(vr_aclk_waiting,false);
+						set(hotspot[vr_cursor].crop,'0|0|80|80');
+						<!-- call onclick -->
+						callwith(caller, scope(global, ondown();onup();onclick(); ); );
+					);
+				);
+			);
+		);
+	</action>
+
+
+	<!-- by pressing SPACE the headset could be re-centered -->
+	<events name="webvr_events" devices="html5" keep="true"
+	        onmousedown="if(webvr AND webvr.isenabled, webvr_showbuttons() );"
+	        />
+
+
+
+	<!-- when WebVR support is available show an EnterVR button -->
+	<action name="webvr_onavailable">
+		webvr.loadsettings();
+		if(layer[webvr_enterbutton], delayedcall(0.5, tween(layer[webvr_enterbutton].alpha,1.0); ); );
+	</action>
+	
+	
+	<action name="webvr_onunknowndevice">
+		if(webvr.isfake AND device.desktop AND webvr.havesettings == false,
+			<!-- set the 'no distortion' headset for fake desktop usage -->
+			set(webvr.mobilevr_lens_overlap, 1.0);
+			set(webvr.mobilevr_lens_fov, 96.0);
+			set(webvr.mobilevr_lens_dist, 0.0);
+			set(webvr.mobilevr_lens_dist2, '1|0|0|0');
+			set(webvr.mobilevr_lens_ca, 0.0);
+			set(webvr.mobilevr_lens_vign, 100);
+		  );
+	</action>
+
+
+	<action name="webvr_onentervr">
+		if(layer[webvr_enterbutton], tween(layer[webvr_enterbutton].alpha,0,0); );
+
+		webvr_showbuttons();
+		webvr_hide_all_non_vr_layers();
+
+		if(webvr.isfake, webvr_show_fakemode_info(true); );
+		
+		webvr_load_vr_cursor_hs();
+	</action>
+
+
+	<action name="webvr_onexitvr">
+		removehotspot('vr_cursor');
+		removehotspot('vr_controller_l');
+		removehotspot('vr_controller_r');
+		set(have_vr_controllers, false);
+		
+		stopdelayedcall(vr_button_fadeout);
+
+		if(layer[webvr_enterbutton], tween(layer[webvr_enterbutton].alpha,1); );
+		tween(layer[webvr_exitbutton].alpha,0);
+		tween(layer[webvr_setupbutton].alpha,0);
+		
+		webvr_show_fakemode_info(false);
+
+		webvr_restore_layers();
+	</action>
+
+
+	<action name="webvr_hide_all_non_vr_layers" scope="local">
+		for(set(i,0), i LT layer.count, inc(i),
+			copy(lr, layer[get(i)]);
+			if(lr.vr !== true,
+				copy(lr.vr_backup_visible, lr.visible);
+				set(lr.visible, false);
+			);
+		);
+	</action>
+
+	<action name="webvr_restore_layers" scope="local">
+		for(set(i,0), i LT layer.count, inc(i),
+			copy(lr, layer[get(i)]);
+			if(lr.vr_backup_visible,
+				copy(lr.visible, lr.vr_backup_visible);
+				delete(lr.vr_backup_visible);
+			);
+		);
+	</action>
+	
+	<action name="webvr_show_fakemode_info" scope="local" args="show">
+		if(show == true,
+			addlayer(webvr_fakemode_info);
+			set(layer[webvr_fakemode_info],
+				type='text',
+				keep=true,
+				align='bottom',
+				y=80,
+				bg=false,
+				css='color:#FFFFFF;text-align:center;',
+				html='[i][u]Simulated WebVR Mode![/u][br]For real WebVR with headset tracking use a [a href="http://webvr.info" target="_blank" style="color:#FFFFFF;"]WebVR-capable[/a] browser or a mobile device and a VR headset.[/i]'
+			);
+		  ,
+			removelayer(webvr_fakemode_info);
+		);
+	</action>
+	
+	
+	<!-- ensure the same scaling on mobiles (regardless if mobilescale is 0.5 or 1.0) -->
+	<krpano webvr_setup_scale="calc:(1.0 + 1.0*(device.mobile AND stagescale LT 1.0)) / (1.0 + 1.0*device.mobile)"
+	        webvr_button_scale.normal="1.0"
+	        webvr_button_scale.mobile="1.6"
+	        />
+
+	
+	<!-- the EnterVR/ExitVR and SetupVR buttons -->
+	<style name="webvr_button_style"
+	       type="text"
+	       bgcolor="0x000000"
+	       bgalpha="0.5"
+	       bgroundedge="0"
+	       css="calc:'color:#FFFFFF;font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       padding="calc:6*webvr_setup_scale*webvr_button_scale + ' ' + 10*webvr_setup_scale*webvr_button_scale"
+	       />
+	
+	<layer name="webvr_enterbutton" keep="true" vr="true"
+	       style="webvr_button_style"
+	       html="Enter VR"
+	       align="top" y="24"
+	       autoalpha="true" alpha="0.0"
+	       onclick="webvr.enterVR();"
+	       />
+
+	<layer name="webvr_exitbutton" keep="true" vr="true"
+	       style="webvr_button_style"
+	       html="Exit VR"
+	       align="top" y="24"
+	       autoalpha="true" alpha="0.0"
+	       onclick="webvr.exitVR();"
+	       />
+
+	<layer name="webvr_setupbutton" keep="true" vr="true"
+	       style="webvr_button_style"
+	       html="VR Setup"
+	       align="bottom" y="24"
+	       autoalpha="true" alpha="0.0"
+	       onclick="vrsetup_open();"
+	       />
+
+
+	<action name="webvr_showbuttons">
+		stopdelayedcall(vr_button_fadeout);
+		tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 1.0|1.0, 0.25);
+		delayedcall(vr_button_fadeout, 3.0, tween(layer[webvr_exitbutton].alpha|layer[webvr_setupbutton].alpha, 0.0|0.0, 1.0); );
+	</action>
+
+	
+		
+	<!-- VR SETUP -->
+	
+	
+	<mobilevr_presets>
+		<headset name="cbv1" caption="Cardboard V1"  profile="80|60|42|35|0.441|0.156" />
+		<headset name="cbv2" caption="Cardboard V2"  profile="120|64|39|35|0.34|0.55" />
+		<headset name="dydm" caption="Daydream"      profile="104|60|41|35|0.42|0.51" />
+		<headset name="nodt" caption="No Distortion" profile="90|60|42|0|0|0" />
+	</mobilevr_presets>
+
+	<action name="vrsetup_open">
+		if(!vrsetup_open_js, vrsetup_init(); );
+		vrsetup_open_js();
+	</action>
+		
+
+	<action name="vrsetup_init" type="Javascript"><![CDATA[
+		
+		var webvr = krpano.webvr;
+		var padding = 20;
+		
+		function vrsetup_dlg_create(type)
+		{
+			var dlg = {type:type, bg:null, y:0, scale:1, elements:[]};
+		
+			if (type == 'layer')
+			{
+				dlg.bg = krpano.addlayer();
+				dlg.bg.keep = true;
+				dlg.bg.type = 'container';
+				dlg.bg.align = 'center';
+			}
+			else	// 'hotspot'
+			{
+				dlg.scale = 0.15;
+				dlg.bg = krpano.addhotspot();
+				dlg.bg.keep = true;
+				dlg.bg.type = 'text';
+				dlg.bg.distorted = true;
+				dlg.bg.ath = krpano.view.hlookat;
+				dlg.bg.atv = 0;
+				dlg.bg.depth = 150;
+				dlg.bg.torigin = 'world';
+				dlg.bg.tx = krpano.view.tx;
+				dlg.bg.ty = krpano.view.ty;
+				dlg.bg.tz = krpano.view.tz;
+			}
+			
+			dlg.bg.bgcolor = 0x000000;
+			dlg.bg.bgalpha = 0.5;
+			dlg.bg.bgcapture = true;
+			dlg.bg.handcursor = false;
+			dlg.bg.capture = false;
+			dlg.bg.zorder = 100;
+			dlg.bg.visible = false;
+			
+			dlg.y = 0;
+			
+			return dlg;
+		}
+		
+		function vrsetup_dlg_addline(dlg, linetext, customcss, onclick)
+		{
+			var txt;
+			
+			if (dlg.type == 'layer')
+			{
+				txt = krpano.addlayer();
+				txt.keep = true;
+				txt.type = 'text';
+				txt.align = 'center';
+				txt.zorder = 101;
+			}
+			else	// 'hotspot'
+			{
+				txt = krpano.addhotspot();
+				txt.keep = true;
+				txt.type = 'text';
+				txt.distorted = true;
+				txt.zorder = 101;
+				txt.ath = dlg.bg.ath;
+				txt.atv = dlg.bg.atv;
+				txt.depth = dlg.bg.depth - 1;
+				txt.oversampling = 2;
+				txt.scale = dlg.scale;
+				txt.torigin = dlg.bg.torigin;
+				txt.tx = dlg.bg.tx;
+				txt.ty = dlg.bg.ty;
+				txt.tz = dlg.bg.tz;
+			}
+			
+			txt.onautosized = function()
+			{
+				txt.havesize = true;
+			}
+			
+			txt.edge = 'top';
+			txt.visible = false;
+			txt.bg = false;
+			txt.html = "" + linetext;
+			txt.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;' + (customcss || '');
+			
+			if (onclick)
+			{
+				txt.onclick = onclick;
+			}
+			else
+			{
+				txt.enabled = false;
+			}
+			
+			dlg.elements.push( txt );
+			
+			return txt;
+		}
+		
+		function vrsetup_dlg_addctrl(dlg, changedelay, callback)
+		{
+			var txt = vrsetup_dlg_addline(dlg, callback(0) );
+			
+			var inc;
+			var dec;
+			
+			if(dlg.type == 'layer')
+			{
+				inc = krpano.addlayer();
+				inc.keep = true;
+				inc.type = 'text';
+				inc.align = 'center';
+				inc.zorder = 101;
+				
+				dec = krpano.addlayer();
+				dec.keep = true;
+				dec.type = 'text';
+				dec.align = 'center';
+				dec.zorder = 101;
+			}
+			else	// 'hotspot'
+			{
+				inc = krpano.addhotspot();
+				inc.keep = true;
+				inc.type = 'text';
+				inc.distorted = true;
+				inc.zorder = 101;
+				inc.ath = dlg.bg.ath;
+				inc.atv = dlg.bg.atv;
+				inc.depth = dlg.bg.depth - 1;
+				inc.oversampling = 2;
+				inc.scale = dlg.scale;
+				inc.torigin = dlg.bg.torigin;
+				inc.tx = dlg.bg.tx;
+				inc.ty = dlg.bg.ty;
+				inc.tz = dlg.bg.tz;
+				
+				dec = krpano.addhotspot();
+				dec.keep = true;
+				dec.type = 'text';
+				dec.distorted = true;
+				dec.zorder = 101;
+				dec.ath = dlg.bg.ath;
+				dec.atv = dlg.bg.atv;
+				dec.depth = dlg.bg.depth - 1;
+				dec.oversampling = 2;
+				dec.scale = dlg.scale;
+				dec.torigin = dlg.bg.torigin;
+				dec.tx = dlg.bg.tx;
+				dec.ty = dlg.bg.ty;
+				dec.tz = dlg.bg.tz;
+			}
+			
+			inc.edge = 'top';
+			inc.visible = false;
+			inc.bg = false;
+			inc.html = '&#62;';
+			inc.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;';
+			inc.padding = '0 10';
+					
+			dec.edge = 'top';
+			dec.visible = false;
+			dec.bg = false;
+			dec.html = '&#60;';
+			dec.css = 'font-size:32px;font-weight:bold;color:#FFFFFF; line-height:90%;';
+			dec.padding = '0 10';
+			
+			inc.vr_timeout = changedelay * 1000;
+			dec.vr_timeout = changedelay * 1000;
+			inc.ondown = function(){ txt.html = ""+callback(+1); inc.enabled = false; setTimeout(function(){ inc.enabled = true; },0); };
+			dec.ondown = function(){ txt.html = ""+callback(-1); dec.enabled = false; setTimeout(function(){ dec.enabled = true; },0); };
+			
+			txt.ctrlchilds = [inc,dec];
+			
+			txt.updateControl = function()
+			{
+				txt.html = callback(0);
+			}
+			
+			return txt;
+		}
+		
+		function vrsetup_dlg_addspace(dlg, customspace)
+		{
+			dlg.elements.push(customspace|| padding);
+		}
+		
+		function vrsetup_dlg_finish(dlg)
+		{
+			var i, w=0, h=0;
+			var waitforsizes=false;
+			
+			for (i=0; i < dlg.elements.length; i++)
+			{
+				var e = dlg.elements[i];
+				if ( isNaN(e) )
+				{
+					if ( e.havesize )
+					{
+						w = Math.max( w, e.width * 1);
+						h += e.height * 1;
+					}
+					else
+					{
+						waitforsizes = true;
+						break;
+					}
+				}
+				else
+				{
+					h += e;
+				}
+			}
+			
+			if (waitforsizes)
+			{
+				setTimeout( function(){ vrsetup_dlg_finish(dlg); }, 16 ); 
+			}
+			else
+			{
+				var y = 0;
+				
+				dlg.bg.width = Math.ceil((w + padding*2)*dlg.scale);
+				dlg.bg.height = Math.ceil((h + padding*2)*dlg.scale);
+					
+				for (i=0; i < dlg.elements.length; i++)
+				{
+					var e = dlg.elements[i];
+					if ( isNaN(e) )
+					{
+						e.oy = Math.round((-h/2 + y) * dlg.scale);
+						e.visible = true;
+						
+						y += e.height * 1;
+						
+						if (e.ctrlchilds )
+						{
+							for (var j=0; j < e.ctrlchilds.length; j++)
+							{
+								var sube = e.ctrlchilds[j];
+								sube.ox = Math.round(((j&1)-0.5) * (-w) * dlg.scale);
+								sube.oy = e.oy;
+								sube.visible = true;
+							}
+						}
+					}
+					else
+					{
+						y += e;
+					}
+				}
+				
+				dlg.bg.visible = true;
+			}
+		}
+		
+		function vrsetup_dlg_remove(dlg)
+		{
+			var removefu = dlg.type == 'layer' ? krpano.removelayer : krpano.removehotspot;
+			
+			var i,j;
+			for (i=0; i < dlg.elements.length; i++)
+			{
+				var e = dlg.elements[i];
+				if ( isNaN(e) )
+				{
+					if (e.ctrlchilds )
+					{
+						for (j=0; j < e.ctrlchilds.length; j++)
+						{
+							var sube = e.ctrlchilds[j];
+							removefu(sube.name);
+						}
+					}
+					
+					removefu(e.name);
+				}
+			}
+			
+			removefu(dlg.bg.name);
+		}
+		
+		
+		function vrsetup_webvr_dialog()
+		{
+			// WebVR API rendering
+			var dlg = vrsetup_dlg_create('hotspot');
+			vrsetup_dlg_addline(dlg, 'WebVR Setup');
+			vrsetup_dlg_addspace(dlg);
+			
+			vrsetup_dlg_addline(dlg, 'Oversampling:', 'font-size:16px;')
+			var ctrl_ss = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
+			{
+				var p = webvr.oversampling;
+				
+				if (change < 0) { p = Math.max(0.2, Number(p) - 0.1); webvr.oversampling = p;  } else 
+				if (change > 0) { p = Math.min(4.0, Number(p) + 0.1); webvr.oversampling = p;  }
+				
+				krpano.actions.delayedcall(0.3, function()
+				{
+					renderres.html = webvr.renderwidth + "x" + webvr.renderheight;
+				});
+				
+				return p.toFixed(1);
+			});
+			vrsetup_dlg_addspace(dlg,8);
+			vrsetup_dlg_addline(dlg, 'Rendering Resolution:', 'font-size:16px;');
+			var renderres = vrsetup_dlg_addline(dlg, '');
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
+			vrsetup_dlg_finish(dlg);
+			
+			return dlg;
+		}
+		
+		function vrsetup_mobilevr_dialog()
+		{
+			// MobileVR / Cardboard rendering
+			var dlg = vrsetup_dlg_create(0 ? 'hotspot' : 'layer');
+			vrsetup_dlg_addline(dlg, 'MobileVR SETUP');
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'Screensize (inch):', 'font-size:16px;')
+			vrsetup_dlg_addctrl(dlg, 1.0, function(change){ var ss = Number(webvr.mobilevr_screensize); if (isNaN(ss)) ss = 5.0; if (change < 0) { ss = Math.max(4.0, ss - 0.1); webvr.mobilevr_screensize = ss; } else if (change > 0) { ss = Math.min(10.0, ss + 0.1); webvr.mobilevr_screensize = ss; } return ss.toFixed(1); });
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'VR Headset Preset:', 'font-size:16px;')
+			var ctrl_ps = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
+			{
+				var preset_index = -1;
+				var i;
+				
+				var profile = webvr.mobilevr_profile;
+				var presets = krpano.get("mobilevr_presets.headset");
+				if (presets)
+				{
+					presets = presets.getArray();
+					
+					for (i=0; i < presets.length; i++)
+					{
+						if ( profile == presets[i].profile )
+						{
+							preset_index = i;
+							break;
+						}
+					}
+					
+					if (change < 0)
+					{
+						preset_index--;
+						if (preset_index < 0)
+							preset_index = presets.length - 1;
+								
+						webvr.mobilevr_profile = presets[preset_index].profile;
+					}
+					else if (change > 0)
+					{
+						preset_index++;
+						if (preset_index >= presets.length)
+							preset_index = 0;
+						
+						webvr.mobilevr_profile = presets[preset_index].profile;
+					}
+				}
+					
+				if (preset_index >= 0)
+				{
+					return presets[preset_index].caption;
+				}
+				
+				return 'Custom';
+			});
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'Customize Headset', 'font-size:25px;', function()
+			{
+				vrsetup_dlg_remove(dlg); 
+				dlg=null; 
+				
+				vrsetup_dialog = vrsetup_mobilevr_interactive_dialog();
+				
+			});
+			vrsetup_dlg_addline(dlg, '(Interactive Adjustment in VR)', 'font-size:12px;');
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
+			vrsetup_dlg_finish(dlg);
+			
+			return dlg;
+		}
+		
+		function vrsetup_mobilevr_interactive_dialog()
+		{
+			// MobileVR / Cardboard rendering
+			var ctrl_preset, ctrl_fov, ctrl_ild, ctrl_stl, ctrl_ttl, ctrl_k1, ctrl_k2, ctrl_os;
+			
+			var dlg = vrsetup_dlg_create('hotspot');
+			vrsetup_dlg_addline(dlg, 'MobileVR SETUP');
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'Preset:', 'font-size:16px;')
+			
+			ctrl_preset = vrsetup_dlg_addctrl(dlg, 1.0, function(change)
+			{
+				var preset_index = -1;
+				var i;
+				
+				var profile = webvr.mobilevr_profile;
+				var presets = krpano.get("mobilevr_presets.headset");
+				if (presets)
+				{
+					presets = presets.getArray();
+					
+					for (i=0; i < presets.length; i++)
+					{
+						if ( profile == presets[i].profile )
+						{
+							preset_index = i;
+							break;
+						}
+					}
+					
+					if (change < 0)
+					{
+						preset_index--;
+						if (preset_index < 0)
+							preset_index = presets.length - 1;
+								
+						webvr.mobilevr_profile = presets[preset_index].profile;
+					}
+					else if (change > 0)
+					{
+						preset_index++;
+						if (preset_index >= presets.length)
+							preset_index = 0;
+						
+						webvr.mobilevr_profile = presets[preset_index].profile;
+					}
+					
+					if (change != 0)
+					{
+						ctrl_fov.updateControl();
+						ctrl_ild.updateControl();
+						ctrl_stl.updateControl();
+						if (ctrl_ttl) ctrl_ttl.updateControl();
+						ctrl_k1.updateControl();
+						ctrl_k2.updateControl();
+					}
+				}
+			
+				if (preset_index >= 0)
+				{
+					return presets[preset_index].caption;
+				}
+				
+				return 'Custom';
+			});
+			
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'Lens-Field-of-View:', 'font-size:16px;');
+			ctrl_fov = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[0] = Number(p[0]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[0] = Number(p[0]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[0]).toFixed(0); });
+			vrsetup_dlg_addspace(dlg, 8);
+			vrsetup_dlg_addline(dlg, 'Inter-Lens-Distance (mm):', 'font-size:16px;');
+			ctrl_ild = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[1] = Number(p[1]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[1] = Number(p[1]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[1]).toFixed(0); });
+			vrsetup_dlg_addspace(dlg, 8);
+			vrsetup_dlg_addline(dlg, 'Screen-to-Lens-Distance (mm):', 'font-size:16px;');
+			ctrl_stl = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[2] = Number(p[2]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[2] = Number(p[2]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[2]).toFixed(0); });
+			vrsetup_dlg_addspace(dlg, 8);
+			if (!webvr.isfake)
+			{
+				vrsetup_dlg_addline(dlg, 'Tray-to-Lens-Center-Distance: (mm):', 'font-size:16px;');
+				ctrl_ttl = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[3] = Number(p[3]) - 1.0; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[3] = Number(p[3]) + 1.0; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[3]).toFixed(0); });
+				vrsetup_dlg_addspace(dlg, 8);
+			}
+			vrsetup_dlg_addline(dlg, 'Lens-Distortion Coefficients:', 'font-size:16px;');
+			ctrl_k1 = vrsetup_dlg_addctrl(dlg, 0.1, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[4] = Number(p[4]) - 0.01; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[4] = Number(p[4]) + 0.01; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[4]).toFixed(3); });
+			ctrl_k2 = vrsetup_dlg_addctrl(dlg, 0.1, function(change){ var p = webvr.mobilevr_profile.split("|"); if (change < 0) { p[5] = Number(p[5]) - 0.01; webvr.mobilevr_profile = p.join("|"); } else if (change > 0) { p[5] = Number(p[5]) + 0.01; webvr.mobilevr_profile = p.join("|"); } if (change != 0) ctrl_preset.updateControl(); return Number(p[5]).toFixed(3); });
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'Oversampling:', 'font-size:16px;');
+			ctrl_os = vrsetup_dlg_addctrl(dlg, 0.25, function(change){ var p = webvr.oversampling; if (change < 0) { p = Math.max(0.2, Number(p) - 0.1); webvr.oversampling = p;  } else if (change > 0) { p = Math.min(4.0, Number(p) + 0.1); webvr.oversampling = p;  } return p.toFixed(1); });
+			vrsetup_dlg_addspace(dlg);
+			vrsetup_dlg_addline(dlg, 'CLOSE', '', vrsetup_close);
+			vrsetup_dlg_finish(dlg);
+			
+			return dlg;
+		}
+		
+		var vrsetup_dialog = null;
+		var vrsetup_events = null;
+		
+		function vrsetup_close()
+		{
+			if (vrsetup_dialog)
+			{
+				webvr.savesettings();
+			
+				vrsetup_dlg_remove(vrsetup_dialog); 
+				vrsetup_dialog = null;
+			}
+		
+			if (vrsetup_events)
+			{
+				krpano.events.removeItem(vrsetup_events.name);
+				vrsetup_events = null;
+			}
+		}
+		
+		krpano.vrsetup_close = function()
+		{
+			vrsetup_close();
+		}
+		
+		krpano.vrsetup_open_js = function()
+		{
+			if (vrsetup_dialog != null)
+			{
+				// already open...
+				return;
+			}
+				
+			if (webvr.iswebvr)
+			{
+				vrsetup_dialog = vrsetup_webvr_dialog();
+			}
+			else
+			{
+				vrsetup_dialog = vrsetup_mobilevr_dialog();
+			}
+			
+			vrsetup_events = krpano.events.createItem("auto");
+			vrsetup_events.keep = true;
+			
+			vrsetup_events.webvr_onexitvr = function()
+			{
+				vrsetup_close();
+			}
+		}
+		
+	]]></action>
+	
+
+	<!-- A list of devices and their screensize -->
+	<mobilevr_device_database>
+		<device name="iPhone 5/5S/SE" screen="320x568x2" size="4.0" bevel="3" />
+		<device name="iPhone 6/6S/7/8" screen="375x667x2" size="4.7" />
+		<device name="iPhone 6/6S/7/8 Plus" screen="414x736" size="5.5" />
+		<device name="iPhone 6/6S/7/8 Plus (zoomed)" screen="375x667x3" size="5.5" />
+		<device name="iPhone X/XS/11Pro" screen="375x812x3" size="5.85|5.33" />
+		<device name="iPhone XS/11Pro Max" screen="414x896x3" size="6.46|5.95" />
+		<device name="iPhone XR/11" screen="414x896x2" size="6.06|5.58" />
+		<device name="iPhone 12/12Pro" screen="390x844" size="6.1" />
+		<device name="iPhone 12Pro Max" screen="428x926" size="6.7" />
+		<device name="Samsung S6" ua="sm-g930" size="5.1" />
+		<device name="Samsung S6 Edge" ua="sm-g925" size="5.1" />
+		<device name="Samsung S6 Edge Plus" ua="sm-g928" size="5.7" />
+		<device name="Samsung S7" ua="sm-g930" size="5.1" />
+		<device name="Samsung S7 Edge" ua="sm-g935" size="5.5" />
+		<device name="Samsung S8" ua="sm-g950" size="5.8" />
+		<device name="Samsung S8+" ua="sm-g955" size="6.2" />
+		<device name="Samsung S9" ua="sm-g960" size="5.8" />
+		<device name="Samsung S9+" ua="sm-g965" size="6.2" />
+		<device name="Samsung S10e" ua="sm-g970" size="5.8" />
+		<device name="Samsung S10" ua="sm-g973" size="6.1" />
+		<device name="Samsung S10+" ua="sm-g975" size="6.4" />
+		<device name="Samsung S10 5G" ua="sm-g977" size="6.7" />
+		<device name="Samsung Note 7" ua="sm-n930" size="5.7" />
+		<device name="Samsung Note 8" ua="sm-n950" size="6.3" />
+		<device name="Samsung Note 9" ua="sm-n960" size="6.4" />
+		<device name="Samsung Note 10" ua="sm-n970" size="6.3" />
+		<device name="Samsung Note 10 5G" ua="sm-n971" size="6.3" />
+		<device name="Samsung Note 10+" ua="sm-n975" size="6.8" />
+		<device name="Samsung Note 10+ 5G" ua="sm-n976" size="6.8" />
+		<device name="Huawei P10 Lite" ua="HUAWEIWAS-TL10" size="5.2" />
+		<device name="Huawei P20 Lite" ua="HUAWEIANE-LX1" size="5.84" />
+	</mobilevr_device_database>
+
+</krpano>

BIN
smty/lib/plugins/webvr_handcursor.png


BIN
smty/lib/plugins/webvr_laser.png


BIN
smty/lib/plugins/webvr_light.png


BIN
smty/lib/plugins/webvr_vrcursor.png


BIN
smty/lib/skin/rotate_device.png


BIN
smty/lib/skin/vtourskin.png


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1333 - 0
smty/lib/skin/vtourskin.xml


+ 28 - 0
smty/lib/skin/vtourskin_design_117.xml

@@ -0,0 +1,28 @@
+<krpano>
+
+	<!-- Version 1.17 Design -->
+
+	<skin_settings layout_width="100%"
+	               layout_maxwidth=""
+	               controlbar_width="100%"
+	               controlbar_height.normal="40"
+	               controlbar_height.mobile="38"
+	               controlbar_offset.normal="20"
+	               controlbar_offset.mobile="0"
+	               controlbar_offset_closed="-2"
+	               controlbar_overlap="0"
+	               design_skin_images="vtourskin.png"
+	               design_bgcolor="0x000000"
+	               design_bgalpha="0.5"
+	               design_bgborder="1,0 0xFFFFFF 1"
+	               design_bgroundedge.no-ios="0"
+	               design_bgroundedge.ios="1"
+	               design_bgshadow="0 0 20 0x000000 1.0"
+	               design_thumbborder_bgborder="4 0xFFFFFF 1.0"
+	               design_thumbborder_padding="2"
+	               design_thumbborder_bgroundedge="3"
+	               design_text_css="color:#FFFFFF; font-family:Arial; font-weight:bold;"
+	               design_text_shadow="1"
+	               />
+
+</krpano>

+ 31 - 0
smty/lib/skin/vtourskin_design_117round.xml

@@ -0,0 +1,31 @@
+<krpano>
+
+	<!-- Version 1.17 Round Design -->
+
+	<skin_settings layout_width="100%"
+	               layout_maxwidth.normal="900"
+	               layout_maxwidth.mobile=""
+	               controlbar_width.normal="-44"
+	               controlbar_width.mobile="100%"
+	               controlbar_height.normal="38"
+	               controlbar_height.mobile="34"
+	               controlbar_offset.normal="22"
+	               controlbar_offset.mobile="0"
+	               controlbar_offset_closed="-40"
+	               controlbar_overlap.normal="7"
+	               controlbar_overlap.mobile="2"
+	               design_skin_images="vtourskin.png"
+	               design_bgcolor="0x000000"
+	               design_bgalpha="0.5"
+	               design_bgborder="0 0xFFFFFF 1.0"
+	               design_bgroundedge.normal="9"
+	               design_bgroundedge.mobile="1"
+	               design_bgshadow="0 0 9 0xFFFFFF 0.5"
+	               design_thumbborder_bgborder="4 0xFFFFFF 1.0"
+	               design_thumbborder_padding="2"
+	               design_thumbborder_bgroundedge="5"
+	               design_text_css="color:#FFFFFF; font-family:Arial; font-weight:bold;"
+	               design_text_shadow="1"
+	               />
+
+</krpano>

+ 71 - 0
smty/lib/skin/vtourskin_design_black.xml

@@ -0,0 +1,71 @@
+<krpano>
+
+	<!-- Flat Light Design -->
+
+	<!-- modify the <skin_settings> values -->
+	<skin_settings layout_width="100%"
+	               layout_maxwidth="100%"
+	               controlbar_width="100%"
+	               controlbar_height="40"
+	               controlbar_offset.normal="0"
+	               controlbar_offset.mobile="0"
+	               controlbar_offset_closed="-40"
+	               controlbar_overlap.no-fractionalscaling="0"
+	               controlbar_overlap.fractionalscaling="0"
+	               design_skin_images="vtourskin.png"
+	               design_bgcolor="0x000000"
+	               design_bgalpha="1.0"
+	               design_bgborder="0"
+	               design_bgroundedge="0"
+	               design_bgshadow="0 4 10 0xFFFFFF 0.3"
+	               design_thumbborder_bgborder="3 0xB2B2B2 1.0"
+	               design_thumbborder_padding="2"
+	               design_thumbborder_bgroundedge="0"
+	               design_text_css="color:#FFFFFF; font-family:Arial;"
+	               design_text_shadow="0"
+	               />
+
+	<!-- adjust the design of some skin elements  -->
+	<layer name="skin_layer">
+		<layer name="skin_loadingtext" width="100%" css="calc:skin_settings.design_text_css + ' text-align:center; font-size:20px;'" padding="4 6" textshadow="calc:2.0" textshadowrange="1.0" textshadowangle="90" textshadowcolor="0x2D3E50" textshadowalpha="1.0" />
+		<layer name="skin_control_bar" alpha="0.7" />
+	</layer>
+
+
+	<!-- use a fullscreen map -->
+	<action name="skin_showmap">
+		if(%1 == null, if(layer[skin_map].state == 'closed', set(show,true), set(show,false)); , set(show,%1); );
+		mul(mh, layer[skin_scroll_layer].pixelheight, -1);
+		if(show,
+			tween(layer[skin_thumbs_container].alpha, 0.0, 0.25, default, set(layer[skin_thumbs_container].visible,false));
+			set(layer[skin_map].visible, true);
+			tween(layer[skin_map].alpha, 1.0, 0.25);
+			set(layer[skin_map].state, 'opened');
+			sub(hh,area.pixelheight,skin_settings.controlbar_offset);
+			sub(hh,layer[skin_control_bar].height);
+			sub(hh,0);
+			add(mh,hh);
+			sub(hh,skin_settings.controlbar_overlap);
+			copy(layer[skin_map].height, hh);
+			tween(layer[skin_scroll_layer].y, get(mh), 0.5, easeOutQuint);
+		  ,
+		  	if(layer[skin_map].state != 'closed',
+				set(layer[skin_map].state, 'closed');
+				add(mh, layer[skin_scroll_layer].y_offset);
+				tween(layer[skin_map].alpha, 0.0, 0.5, easeOutQuint);
+				tween(layer[skin_scroll_layer].y, get(mh), 0.5, easeOutQuint, set(layer[skin_map].visible,false) );
+			  );
+		  );
+	</action>
+
+
+	<!-- webvr button style (adjust to match skin style) -->
+	<style name="webvr_button_style"
+	       border="false"
+	       roundedge="calc:1.0"
+	       backgroundcolor="get:skin_settings.design_bgcolor" backgroundalpha="get:skin_settings.design_bgalpha"
+	       shadow="0.01" shadowrange="10.0" shadowangle="90.0" shadowcolor="0x30261B" shadowalpha="0.50"
+	       css="calc:skin_settings.design_text_css + ' font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       />
+
+</krpano>

+ 42 - 0
smty/lib/skin/vtourskin_design_flat_light.xml

@@ -0,0 +1,42 @@
+<krpano>
+
+	<!-- Flat Light Design -->
+
+	<!-- modify the <skin_settings> values -->
+	<skin_settings layout_width="100%"
+	               layout_maxwidth="814"
+	               controlbar_width="-24"
+	               controlbar_height="40"
+	               controlbar_offset.normal="20"
+	               controlbar_offset.mobile="20"
+	               controlbar_offset_closed="-40"
+	               controlbar_overlap.no-fractionalscaling="10"
+	               controlbar_overlap.fractionalscaling="0"
+	               design_skin_images="vtourskin_light.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="2 0xFFFFFF 0.8"
+	               design_thumbborder_padding="2"
+	               design_thumbborder_bgroundedge="0"
+	               design_text_css="color:#FFFFFF; font-family:Arial; font-weight:lighter;"
+	               design_text_shadow="1"
+	               />
+
+	<!-- adjust the design of some skin elements  -->
+	<layer name="skin_layer">
+		<layer name="skin_loadingtext" width="100%" css="calc:skin_settings.design_text_css + ' text-align:center; font-size:20px;'" padding="4 6" textshadow="calc:2.0" textshadowrange="1.0" textshadowangle="90" textshadowcolor="0x2D3E50" textshadowalpha="1.0" />
+	</layer>
+
+	<!-- webvr button style (adjust to match skin style) -->
+	<style name="webvr_button_style"
+	       border="false"
+	       roundedge="calc:1.0"
+	       backgroundcolor="get:skin_settings.design_bgcolor" backgroundalpha="get:skin_settings.design_bgalpha"
+	       shadow="0.01" shadowrange="10.0" shadowangle="90.0" shadowcolor="0x30261B" shadowalpha="0.50"
+	       css="calc:skin_settings.design_text_css + ' font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       />
+
+</krpano>

+ 40 - 0
smty/lib/skin/vtourskin_design_glass.xml

@@ -0,0 +1,40 @@
+<krpano>
+
+	<!-- Glass Design -->
+
+	<!-- modify the <skin_settings> values -->
+	<skin_settings thumbs_scrollindicator="true"
+	               layout_width="100%"
+	               layout_maxwidth="680"
+	               xcontrolbar_width="-44"
+	               controlbar_width="-20"
+	               controlbar_height="36"
+	               controlbar_offset.normal="40"
+	               controlbar_offset.mobile="12"
+	               controlbar_offset_closed="-40"
+	               controlbar_overlap="10"
+	               design_skin_images="vtourskin.png"
+	               design_bgcolor="0xFFFFFF"
+	               design_bgalpha="0.25"
+	               design_bgborder="2 0xFFFFFF 0.1"
+	               design_bgroundedge="13"
+	               design_bgshadow="0"
+	               design_thumbborder_bgborder="3 0xFFFFFF 1.0"
+	               design_thumbborder_padding="2"
+	               design_thumbborder_bgroundedge="5"
+	               design_text_css="color:#FFFFFF; font-family:Arial; font-weight:bold;"
+	               design_text_shadow="0"
+	               />
+
+	<!-- webvr button style (adjust to match default skin style) -->
+	<style name="webvr_button_style"
+	       border="true" borderwidth="2" bordercolor="0xFFFFFF" borderalpha="0.25"
+	       backgroundcolor="get:skin_settings.design_bgcolor" backgroundalpha="get:skin_settings.design_bgalpha"
+	       shadow="0"
+	       css="calc:skin_settings.design_text_css + ' color:#FFFFFF; font-weight:normal; font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       />
+
+	<!-- contextmenu style (adjust to match skin style) -->
+	<contextmenu customstyle="default|default|default|0x77AAAAAA|0xFFFFFF|0xBBBBBB|2|0x7FFFFFFF|13|0|0|0|0xFFFFFF|0|0|4|6|7|0xAAFFFFFF|none|3|0|0|0|3|0xAAFFFFFF|0xAAFFFFFF|0xFFFFFF|12|8" />
+
+</krpano>

+ 58 - 0
smty/lib/skin/vtourskin_design_ultra_light.xml

@@ -0,0 +1,58 @@
+<krpano>
+
+	<!-- Ultra Light Design -->
+
+	<!-- modify the <skin_settings> values -->
+	<skin_settings title="false"
+	               layout_width="100%"
+	               layout_maxwidth="814"
+	               controlbar_width="-24"
+	               controlbar_height="40"
+	               controlbar_offset.normal="30"
+	               controlbar_offset.mobile="20"
+	               controlbar_offset_closed="-40"
+	               controlbar_overlap="0"
+	               design_skin_images="vtourskin_light.png"
+	               design_bgcolor="0x2D3E50"
+	               design_bgalpha="0.0"
+	               design_bgborder="0,0,1,0 0xFFFFFF 1"
+	               design_bgroundedge="0"
+	               design_bgshadow="0"
+	               design_thumbborder_bgborder="1 0xFFFFFF 0.8"
+	               design_thumbborder_padding="0"
+	               design_thumbborder_bgroundedge="0"
+	               design_text_css="color:#FFFFFF; font-family:Arial; font-weight:lighter;"
+	               design_text_shadow="0"
+	               />
+
+	<!-- webvr button style (adjust to match skin style) -->
+	<style name="webvr_button_style"
+	       border="false"
+	       roundedge="calc:1.0"
+	       backgroundcolor="get:skin_settings.design_bgcolor" backgroundalpha="get:skin_settings.design_bgalpha"
+	       shadow="0.01" shadowrange="10.0" shadowangle="90.0" shadowcolor="0x30261B" shadowalpha="0.50"
+	       css="calc:skin_settings.design_text_css + ' font-size:' + 20*webvr_setup_scale*webvr_button_scale + 'px;'"
+	       />
+
+	<!-- adjust video controls to match skin style -->
+	<layer name="skin_layer">
+		<layer name="skin_scroll_window">
+			<layer name="skin_scroll_layer">
+				<layer name="skin_video_controls">
+					<layer name="skin_video_seekbar_container">
+						<layer name="skin_video_seekbar" height="1" y="4">
+							<layer name="skin_video_loadbar" height="1" />
+							<layer name="skin_video_seekpos" bgroundedge="2" width="6" height="6" />
+						</layer>
+					</layer>
+					<layer name="skin_video_time" y="-4" />
+				</layer>
+			</layer>
+		</layer>
+	</layer>
+					
+
+	<!-- contextmenu style (adjust to match skin style) -->
+	<contextmenu customstyle="default|default|default|0x7F000000|0xFFFFFF|0xBBBBBB|0|0x20FFFFFF|1|0|0|0|0xFFFFFF|0|0xFFFFFF|4|6|7|0xAAFFFFFF|none|3|0|0|0|3|0xFFFFFF|0xFFFFFF|0x000000|12|8" />
+
+</krpano>

BIN
smty/lib/skin/vtourskin_hotspot.png


BIN
smty/lib/skin/vtourskin_light.png


BIN
smty/lib/skin/vtourskin_mapspot.png


BIN
smty/lib/skin/vtourskin_mapspotactive.png


+ 801 - 0
smty/lib/tween.umd.js

@@ -0,0 +1,801 @@
+(function (global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+    typeof define === 'function' && define.amd ? define(factory) :
+    (global.TWEEN = factory());
+}(this, (function () { 'use strict';
+
+    var NOW;
+    // Include a performance.now polyfill.
+    // In node.js, use process.hrtime.
+    // eslint-disable-next-line
+    // @ts-ignore
+    if (typeof self === 'undefined' && typeof process !== 'undefined' && process.hrtime) {
+        NOW = function () {
+            // eslint-disable-next-line
+            // @ts-ignore
+            var time = process.hrtime();
+            // Convert [seconds, nanoseconds] to milliseconds.
+            return time[0] * 1000 + time[1] / 1000000;
+        };
+    }
+    // In a browser, use self.performance.now if it is available.
+    else if (typeof self !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) {
+        // This must be bound, because directly assigning this function
+        // leads to an invocation exception in Chrome.
+        NOW = self.performance.now.bind(self.performance);
+    }
+    // Use Date.now if it is available.
+    else if (Date.now !== undefined) {
+        NOW = Date.now;
+    }
+    // Otherwise, use 'new Date().getTime()'.
+    else {
+        NOW = function () {
+            return new Date().getTime();
+        };
+    }
+    var NOW$1 = NOW;
+
+    /**
+     * Controlling groups of tweens
+     *
+     * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components.
+     * In these cases, you may want to create your own smaller groups of tween
+     */
+    var Group = /** @class */ (function () {
+        function Group() {
+            this._tweens = {};
+            this._tweensAddedDuringUpdate = {};
+        }
+        Group.prototype.getAll = function () {
+            var _this = this;
+            return Object.keys(this._tweens).map(function (tweenId) {
+                return _this._tweens[tweenId];
+            });
+        };
+        Group.prototype.removeAll = function () {
+            this._tweens = {};
+        };
+        Group.prototype.add = function (tween) {
+            this._tweens[tween.getId()] = tween;
+            this._tweensAddedDuringUpdate[tween.getId()] = tween;
+        };
+        Group.prototype.remove = function (tween) {
+            delete this._tweens[tween.getId()];
+            delete this._tweensAddedDuringUpdate[tween.getId()];
+        };
+        Group.prototype.update = function (time, preserve) {
+            var tweenIds = Object.keys(this._tweens);
+            if (tweenIds.length === 0) {
+                return false;
+            }
+            time = time !== undefined ? time : NOW$1();
+            // Tweens are updated in "batches". If you add a new tween during an
+            // update, then the new tween will be updated in the next batch.
+            // If you remove a tween during an update, it may or may not be updated.
+            // However, if the removed tween was added during the current batch,
+            // then it will not be updated.
+            while (tweenIds.length > 0) {
+                this._tweensAddedDuringUpdate = {};
+                for (var i = 0; i < tweenIds.length; i++) {
+                    var tween = this._tweens[tweenIds[i]];
+                    if (tween && tween.update(time) === false && !preserve) {
+                        delete this._tweens[tweenIds[i]];
+                    }
+                }
+                tweenIds = Object.keys(this._tweensAddedDuringUpdate);
+            }
+            return true;
+        };
+        return Group;
+    }());
+
+    /**
+     * The Ease class provides a collection of easing functions for use with tween.js.
+     */
+    var Easing = {
+        Linear: {
+            None: function (amount) {
+                return amount;
+            },
+        },
+        Quadratic: {
+            In: function (amount) {
+                return amount * amount;
+            },
+            Out: function (amount) {
+                return amount * (2 - amount);
+            },
+            InOut: function (amount) {
+                if ((amount *= 2) < 1) {
+                    return 0.5 * amount * amount;
+                }
+                return -0.5 * (--amount * (amount - 2) - 1);
+            },
+        },
+        Cubic: {
+            In: function (amount) {
+                return amount * amount * amount;
+            },
+            Out: function (amount) {
+                return --amount * amount * amount + 1;
+            },
+            InOut: function (amount) {
+                if ((amount *= 2) < 1) {
+                    return 0.5 * amount * amount * amount;
+                }
+                return 0.5 * ((amount -= 2) * amount * amount + 2);
+            },
+        },
+        Quartic: {
+            In: function (amount) {
+                return amount * amount * amount * amount;
+            },
+            Out: function (amount) {
+                return 1 - --amount * amount * amount * amount;
+            },
+            InOut: function (amount) {
+                if ((amount *= 2) < 1) {
+                    return 0.5 * amount * amount * amount * amount;
+                }
+                return -0.5 * ((amount -= 2) * amount * amount * amount - 2);
+            },
+        },
+        Quintic: {
+            In: function (amount) {
+                return amount * amount * amount * amount * amount;
+            },
+            Out: function (amount) {
+                return --amount * amount * amount * amount * amount + 1;
+            },
+            InOut: function (amount) {
+                if ((amount *= 2) < 1) {
+                    return 0.5 * amount * amount * amount * amount * amount;
+                }
+                return 0.5 * ((amount -= 2) * amount * amount * amount * amount + 2);
+            },
+        },
+        Sinusoidal: {
+            In: function (amount) {
+                return 1 - Math.cos((amount * Math.PI) / 2);
+            },
+            Out: function (amount) {
+                return Math.sin((amount * Math.PI) / 2);
+            },
+            InOut: function (amount) {
+                return 0.5 * (1 - Math.cos(Math.PI * amount));
+            },
+        },
+        Exponential: {
+            In: function (amount) {
+                return amount === 0 ? 0 : Math.pow(1024, amount - 1);
+            },
+            Out: function (amount) {
+                return amount === 1 ? 1 : 1 - Math.pow(2, -10 * amount);
+            },
+            InOut: function (amount) {
+                if (amount === 0) {
+                    return 0;
+                }
+                if (amount === 1) {
+                    return 1;
+                }
+                if ((amount *= 2) < 1) {
+                    return 0.5 * Math.pow(1024, amount - 1);
+                }
+                return 0.5 * (-Math.pow(2, -10 * (amount - 1)) + 2);
+            },
+        },
+        Circular: {
+            In: function (amount) {
+                return 1 - Math.sqrt(1 - amount * amount);
+            },
+            Out: function (amount) {
+                return Math.sqrt(1 - --amount * amount);
+            },
+            InOut: function (amount) {
+                if ((amount *= 2) < 1) {
+                    return -0.5 * (Math.sqrt(1 - amount * amount) - 1);
+                }
+                return 0.5 * (Math.sqrt(1 - (amount -= 2) * amount) + 1);
+            },
+        },
+        Elastic: {
+            In: function (amount) {
+                if (amount === 0) {
+                    return 0;
+                }
+                if (amount === 1) {
+                    return 1;
+                }
+                return -Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI);
+            },
+            Out: function (amount) {
+                if (amount === 0) {
+                    return 0;
+                }
+                if (amount === 1) {
+                    return 1;
+                }
+                return Math.pow(2, -10 * amount) * Math.sin((amount - 0.1) * 5 * Math.PI) + 1;
+            },
+            InOut: function (amount) {
+                if (amount === 0) {
+                    return 0;
+                }
+                if (amount === 1) {
+                    return 1;
+                }
+                amount *= 2;
+                if (amount < 1) {
+                    return -0.5 * Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI);
+                }
+                return 0.5 * Math.pow(2, -10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI) + 1;
+            },
+        },
+        Back: {
+            In: function (amount) {
+                var s = 1.70158;
+                return amount * amount * ((s + 1) * amount - s);
+            },
+            Out: function (amount) {
+                var s = 1.70158;
+                return --amount * amount * ((s + 1) * amount + s) + 1;
+            },
+            InOut: function (amount) {
+                var s = 1.70158 * 1.525;
+                if ((amount *= 2) < 1) {
+                    return 0.5 * (amount * amount * ((s + 1) * amount - s));
+                }
+                return 0.5 * ((amount -= 2) * amount * ((s + 1) * amount + s) + 2);
+            },
+        },
+        Bounce: {
+            In: function (amount) {
+                return 1 - Easing.Bounce.Out(1 - amount);
+            },
+            Out: function (amount) {
+                if (amount < 1 / 2.75) {
+                    return 7.5625 * amount * amount;
+                }
+                else if (amount < 2 / 2.75) {
+                    return 7.5625 * (amount -= 1.5 / 2.75) * amount + 0.75;
+                }
+                else if (amount < 2.5 / 2.75) {
+                    return 7.5625 * (amount -= 2.25 / 2.75) * amount + 0.9375;
+                }
+                else {
+                    return 7.5625 * (amount -= 2.625 / 2.75) * amount + 0.984375;
+                }
+            },
+            InOut: function (amount) {
+                if (amount < 0.5) {
+                    return Easing.Bounce.In(amount * 2) * 0.5;
+                }
+                return Easing.Bounce.Out(amount * 2 - 1) * 0.5 + 0.5;
+            },
+        },
+    };
+
+    /**
+     *
+     */
+    var Interpolation = {
+        Linear: function (v, k) {
+            var m = v.length - 1;
+            var f = m * k;
+            var i = Math.floor(f);
+            var fn = Interpolation.Utils.Linear;
+            if (k < 0) {
+                return fn(v[0], v[1], f);
+            }
+            if (k > 1) {
+                return fn(v[m], v[m - 1], m - f);
+            }
+            return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);
+        },
+        Bezier: function (v, k) {
+            var b = 0;
+            var n = v.length - 1;
+            var pw = Math.pow;
+            var bn = Interpolation.Utils.Bernstein;
+            for (var i = 0; i <= n; i++) {
+                b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);
+            }
+            return b;
+        },
+        CatmullRom: function (v, k) {
+            var m = v.length - 1;
+            var f = m * k;
+            var i = Math.floor(f);
+            var fn = Interpolation.Utils.CatmullRom;
+            if (v[0] === v[m]) {
+                if (k < 0) {
+                    i = Math.floor((f = m * (1 + k)));
+                }
+                return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i);
+            }
+            else {
+                if (k < 0) {
+                    return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]);
+                }
+                if (k > 1) {
+                    return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);
+                }
+                return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i);
+            }
+        },
+        Utils: {
+            Linear: function (p0, p1, t) {
+                return (p1 - p0) * t + p0;
+            },
+            Bernstein: function (n, i) {
+                var fc = Interpolation.Utils.Factorial;
+                return fc(n) / fc(i) / fc(n - i);
+            },
+            Factorial: (function () {
+                var a = [1];
+                return function (n) {
+                    var s = 1;
+                    if (a[n]) {
+                        return a[n];
+                    }
+                    for (var i = n; i > 1; i--) {
+                        s *= i;
+                    }
+                    a[n] = s;
+                    return s;
+                };
+            })(),
+            CatmullRom: function (p0, p1, p2, p3, t) {
+                var v0 = (p2 - p0) * 0.5;
+                var v1 = (p3 - p1) * 0.5;
+                var t2 = t * t;
+                var t3 = t * t2;
+                return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
+            },
+        },
+    };
+
+    /**
+     * Utils
+     */
+    var Sequence = /** @class */ (function () {
+        function Sequence() {
+        }
+        Sequence.nextId = function () {
+            return Sequence._nextId++;
+        };
+        Sequence._nextId = 0;
+        return Sequence;
+    }());
+
+    /**
+     * Tween.js - Licensed under the MIT license
+     * https://github.com/tweenjs/tween.js
+     * ----------------------------------------------
+     *
+     * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors.
+     * Thank you all, you're awesome!
+     */
+    var Tween = /** @class */ (function () {
+        function Tween(_object, _group) {
+            if (_group === void 0) { _group = TWEEN; }
+            this._object = _object;
+            this._group = _group;
+            this._isPaused = false;
+            this._pauseStart = 0;
+            this._valuesStart = {};
+            this._valuesEnd = {};
+            this._valuesStartRepeat = {};
+            this._duration = 1000;
+            this._initialRepeat = 0;
+            this._repeat = 0;
+            this._yoyo = false;
+            this._isPlaying = false;
+            this._reversed = false;
+            this._delayTime = 0;
+            this._startTime = 0;
+            this._easingFunction = TWEEN.Easing.Linear.None;
+            this._interpolationFunction = TWEEN.Interpolation.Linear;
+            this._chainedTweens = [];
+            this._onStartCallbackFired = false;
+            this._id = TWEEN.nextId();
+            this._isChainStopped = false;
+        }
+        Tween.prototype.getId = function () {
+            return this._id;
+        };
+        Tween.prototype.isPlaying = function () {
+            return this._isPlaying;
+        };
+        Tween.prototype.isPaused = function () {
+            return this._isPaused;
+        };
+        Tween.prototype.to = function (properties, duration) {
+            // to (properties, duration) {
+            for (var prop in properties) {
+                this._valuesEnd[prop] = properties[prop];
+            }
+            if (duration !== undefined) {
+                this._duration = duration;
+            }
+            return this;
+        };
+        Tween.prototype.duration = function (d) {
+            this._duration = d;
+            return this;
+        };
+        Tween.prototype.start = function (time) {
+            if (this._isPlaying) {
+                return this;
+            }
+            // eslint-disable-next-line
+            // @ts-ignore FIXME?
+            this._group.add(this);
+            this._repeat = this._initialRepeat;
+            if (this._reversed) {
+                // If we were reversed (f.e. using the yoyo feature) then we need to
+                // flip the tween direction back to forward.
+                this._reversed = false;
+                for (var property in this._valuesStartRepeat) {
+                    this._swapEndStartRepeatValues(property);
+                    this._valuesStart[property] = this._valuesStartRepeat[property];
+                }
+            }
+            this._isPlaying = true;
+            this._isPaused = false;
+            this._onStartCallbackFired = false;
+            this._isChainStopped = false;
+            this._startTime =
+                time !== undefined ? (typeof time === 'string' ? TWEEN.now() + parseFloat(time) : time) : TWEEN.now();
+            this._startTime += this._delayTime;
+            this._setupProperties(this._object, this._valuesStart, this._valuesEnd, this._valuesStartRepeat);
+            return this;
+        };
+        Tween.prototype._setupProperties = function (_object, _valuesStart, _valuesEnd, _valuesStartRepeat) {
+            for (var property in _valuesEnd) {
+                var startValue = _object[property];
+                var startValueIsArray = Array.isArray(startValue);
+                var propType = startValueIsArray ? 'array' : typeof startValue;
+                var isInterpolationList = !startValueIsArray && Array.isArray(_valuesEnd[property]);
+                // If `to()` specifies a property that doesn't exist in the source object,
+                // we should not set that property in the object
+                if (propType === 'undefined' || propType === 'function') {
+                    continue;
+                }
+                // Check if an Array was provided as property value
+                if (isInterpolationList) {
+                    var endValues = _valuesEnd[property];
+                    if (endValues.length === 0) {
+                        continue;
+                    }
+                    // handle an array of relative values
+                    endValues = endValues.map(this._handleRelativeValue.bind(this, startValue));
+                    // Create a local copy of the Array with the start value at the front
+                    _valuesEnd[property] = [startValue].concat(endValues);
+                }
+                // handle the deepness of the values
+                if ((propType === 'object' || startValueIsArray) && startValue && !isInterpolationList) {
+                    _valuesStart[property] = startValueIsArray ? [] : {};
+                    // eslint-disable-next-line
+                    for (var prop in startValue) {
+                        // eslint-disable-next-line
+                        // @ts-ignore FIXME?
+                        _valuesStart[property][prop] = startValue[prop];
+                    }
+                    _valuesStartRepeat[property] = startValueIsArray ? [] : {}; // TODO? repeat nested values? And yoyo? And array values?
+                    // eslint-disable-next-line
+                    // @ts-ignore FIXME?
+                    this._setupProperties(startValue, _valuesStart[property], _valuesEnd[property], _valuesStartRepeat[property]);
+                }
+                else {
+                    // Save the starting value, but only once.
+                    if (typeof _valuesStart[property] === 'undefined') {
+                        _valuesStart[property] = startValue;
+                    }
+                    if (!startValueIsArray) {
+                        // eslint-disable-next-line
+                        // @ts-ignore FIXME?
+                        _valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings
+                    }
+                    if (isInterpolationList) {
+                        // eslint-disable-next-line
+                        // @ts-ignore FIXME?
+                        _valuesStartRepeat[property] = _valuesEnd[property].slice().reverse();
+                    }
+                    else {
+                        _valuesStartRepeat[property] = _valuesStart[property] || 0;
+                    }
+                }
+            }
+        };
+        Tween.prototype.stop = function () {
+            if (!this._isChainStopped) {
+                this._isChainStopped = true;
+                this.stopChainedTweens();
+            }
+            if (!this._isPlaying) {
+                return this;
+            }
+            // eslint-disable-next-line
+            // @ts-ignore FIXME?
+            this._group.remove(this);
+            this._isPlaying = false;
+            this._isPaused = false;
+            if (this._onStopCallback) {
+                this._onStopCallback(this._object);
+            }
+            return this;
+        };
+        Tween.prototype.end = function () {
+            this.update(Infinity);
+            return this;
+        };
+        Tween.prototype.pause = function (time) {
+            if (this._isPaused || !this._isPlaying) {
+                return this;
+            }
+            this._isPaused = true;
+            this._pauseStart = time === undefined ? TWEEN.now() : time;
+            // eslint-disable-next-line
+            // @ts-ignore FIXME?
+            this._group.remove(this);
+            return this;
+        };
+        Tween.prototype.resume = function (time) {
+            if (!this._isPaused || !this._isPlaying) {
+                return this;
+            }
+            this._isPaused = false;
+            this._startTime += (time === undefined ? TWEEN.now() : time) - this._pauseStart;
+            this._pauseStart = 0;
+            // eslint-disable-next-line
+            // @ts-ignore FIXME?
+            this._group.add(this);
+            return this;
+        };
+        Tween.prototype.stopChainedTweens = function () {
+            for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) {
+                this._chainedTweens[i].stop();
+            }
+            return this;
+        };
+        Tween.prototype.group = function (group) {
+            this._group = group;
+            return this;
+        };
+        Tween.prototype.delay = function (amount) {
+            this._delayTime = amount;
+            return this;
+        };
+        Tween.prototype.repeat = function (times) {
+            this._initialRepeat = times;
+            this._repeat = times;
+            return this;
+        };
+        Tween.prototype.repeatDelay = function (amount) {
+            this._repeatDelayTime = amount;
+            return this;
+        };
+        Tween.prototype.yoyo = function (yoyo) {
+            this._yoyo = yoyo;
+            return this;
+        };
+        Tween.prototype.easing = function (easingFunction) {
+            this._easingFunction = easingFunction;
+            return this;
+        };
+        Tween.prototype.interpolation = function (interpolationFunction) {
+            this._interpolationFunction = interpolationFunction;
+            return this;
+        };
+        Tween.prototype.chain = function () {
+            var tweens = [];
+            for (var _i = 0; _i < arguments.length; _i++) {
+                tweens[_i] = arguments[_i];
+            }
+            this._chainedTweens = tweens;
+            return this;
+        };
+        Tween.prototype.onStart = function (callback) {
+            this._onStartCallback = callback;
+            return this;
+        };
+        Tween.prototype.onUpdate = function (callback) {
+            this._onUpdateCallback = callback;
+            return this;
+        };
+        Tween.prototype.onRepeat = function (callback) {
+            this._onRepeatCallback = callback;
+            return this;
+        };
+        Tween.prototype.onComplete = function (callback) {
+            this._onCompleteCallback = callback;
+            return this;
+        };
+        Tween.prototype.onStop = function (callback) {
+            this._onStopCallback = callback;
+            return this;
+        };
+        Tween.prototype.update = function (time) {
+            var property;
+            var elapsed;
+            var endTime = this._startTime + this._duration;
+            if (time > endTime && !this._isPlaying) {
+                return false;
+            }
+            // If the tween was already finished,
+            if (!this.isPlaying) {
+                this.start(time);
+            }
+            if (time < this._startTime) {
+                return true;
+            }
+            if (this._onStartCallbackFired === false) {
+                if (this._onStartCallback) {
+                    this._onStartCallback(this._object);
+                }
+                this._onStartCallbackFired = true;
+            }
+            elapsed = (time - this._startTime) / this._duration;
+            elapsed = this._duration === 0 || elapsed > 1 ? 1 : elapsed;
+            var value = this._easingFunction(elapsed);
+            // properties transformations
+            this._updateProperties(this._object, this._valuesStart, this._valuesEnd, value);
+            if (this._onUpdateCallback) {
+                this._onUpdateCallback(this._object, elapsed);
+            }
+            if (elapsed === 1) {
+                if (this._repeat > 0) {
+                    if (isFinite(this._repeat)) {
+                        this._repeat--;
+                    }
+                    // Reassign starting values, restart by making startTime = now
+                    for (property in this._valuesStartRepeat) {
+                        if (!this._yoyo && typeof this._valuesEnd[property] === 'string') {
+                            this._valuesStartRepeat[property] =
+                                // eslint-disable-next-line
+                                // @ts-ignore FIXME?
+                                this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]);
+                        }
+                        if (this._yoyo) {
+                            this._swapEndStartRepeatValues(property);
+                        }
+                        this._valuesStart[property] = this._valuesStartRepeat[property];
+                    }
+                    if (this._yoyo) {
+                        this._reversed = !this._reversed;
+                    }
+                    if (this._repeatDelayTime !== undefined) {
+                        this._startTime = time + this._repeatDelayTime;
+                    }
+                    else {
+                        this._startTime = time + this._delayTime;
+                    }
+                    if (this._onRepeatCallback) {
+                        this._onRepeatCallback(this._object);
+                    }
+                    return true;
+                }
+                else {
+                    if (this._onCompleteCallback) {
+                        this._onCompleteCallback(this._object);
+                    }
+                    for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) {
+                        // Make the chained tweens start exactly at the time they should,
+                        // even if the `update()` method was called way past the duration of the tween
+                        this._chainedTweens[i].start(this._startTime + this._duration);
+                    }
+                    this._isPlaying = false;
+                    return false;
+                }
+            }
+            return true;
+        };
+        Tween.prototype._updateProperties = function (_object, _valuesStart, _valuesEnd, value) {
+            for (var property in _valuesEnd) {
+                // Don't update properties that do not exist in the source object
+                if (_valuesStart[property] === undefined) {
+                    continue;
+                }
+                var start = _valuesStart[property] || 0;
+                var end = _valuesEnd[property];
+                var startIsArray = Array.isArray(_object[property]);
+                var endIsArray = Array.isArray(end);
+                var isInterpolationList = !startIsArray && endIsArray;
+                if (isInterpolationList) {
+                    _object[property] = this._interpolationFunction(end, value);
+                }
+                else if (typeof end === 'object' && end) {
+                    // eslint-disable-next-line
+                    // @ts-ignore FIXME?
+                    this._updateProperties(_object[property], start, end, value);
+                }
+                else {
+                    // Parses relative end values with start as base (e.g.: +10, -3)
+                    end = this._handleRelativeValue(start, end);
+                    // Protect against non numeric properties.
+                    if (typeof end === 'number') {
+                        // eslint-disable-next-line
+                        // @ts-ignore FIXME?
+                        _object[property] = start + (end - start) * value;
+                    }
+                }
+            }
+        };
+        Tween.prototype._handleRelativeValue = function (start, end) {
+            if (typeof end !== 'string') {
+                return end;
+            }
+            if (end.charAt(0) === '+' || end.charAt(0) === '-') {
+                return start + parseFloat(end);
+            }
+            else {
+                return parseFloat(end);
+            }
+        };
+        Tween.prototype._swapEndStartRepeatValues = function (property) {
+            var tmp = this._valuesStartRepeat[property];
+            if (typeof this._valuesEnd[property] === 'string') {
+                // eslint-disable-next-line
+                // @ts-ignore FIXME?
+                this._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]);
+            }
+            else {
+                this._valuesStartRepeat[property] = this._valuesEnd[property];
+            }
+            this._valuesEnd[property] = tmp;
+        };
+        return Tween;
+    }());
+
+    var VERSION = '18.5.0';
+
+    /**
+     * Tween.js - Licensed under the MIT license
+     * https://github.com/tweenjs/tween.js
+     * ----------------------------------------------
+     *
+     * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors.
+     * Thank you all, you're awesome!
+     */
+    var __extends = (this && this.__extends) || (function () {
+        var extendStatics = function (d, b) {
+            extendStatics = Object.setPrototypeOf ||
+                ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+                function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+            return extendStatics(d, b);
+        };
+        return function (d, b) {
+            extendStatics(d, b);
+            function __() { this.constructor = d; }
+            d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+        };
+    })();
+    /**
+     * Controlling groups of tweens
+     *
+     * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components.
+     * In these cases, you may want to create your own smaller groups of tween
+     */
+    var Main = /** @class */ (function (_super) {
+        __extends(Main, _super);
+        function Main() {
+            var _this = _super !== null && _super.apply(this, arguments) || this;
+            _this.version = VERSION;
+            _this.now = NOW$1;
+            _this.Group = Group;
+            _this.Easing = Easing;
+            _this.Interpolation = Interpolation;
+            _this.nextId = Sequence.nextId;
+            _this.Tween = Tween;
+            return _this;
+        }
+        return Main;
+    }(Group));
+    var TWEEN = new Main();
+
+    return TWEEN;
+
+})));

+ 131 - 0
smty/lib/vector.js

@@ -0,0 +1,131 @@
+function Vector(x, y, z) {
+    this.x = x || 0;
+    this.y = y || 0;
+    this.z = z || 0;
+  }
+
+  Vector.prototype = {
+    negative: function() {
+      return new Vector(-this.x, -this.y, -this.z);
+    },
+    add: function(v) {
+      if (v instanceof Vector) return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
+      else return new Vector(this.x + v, this.y + v, this.z + v);
+    },
+    subtract: function(v) {
+      if (v instanceof Vector) return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
+      else return new Vector(this.x - v, this.y - v, this.z - v);
+    },
+    multiply: function(v) {
+      if (v instanceof Vector) return new Vector(this.x * v.x, this.y * v.y, this.z * v.z);
+      else return new Vector(this.x * v, this.y * v, this.z * v);
+    },
+    divide: function(v) {
+      if (v instanceof Vector) return new Vector(this.x / v.x, this.y / v.y, this.z / v.z);
+      else return new Vector(this.x / v, this.y / v, this.z / v);
+    },
+    equals: function(v) {
+      return this.x == v.x && this.y == v.y && this.z == v.z;
+    },
+    dot: function(v) {
+      return this.x * v.x + this.y * v.y + this.z * v.z;
+    },
+    cross: function(v) {
+      return new Vector(
+        this.y * v.z - this.z * v.y,
+        this.z * v.x - this.x * v.z,
+        this.x * v.y - this.y * v.x
+      );
+    },
+    length: function() {
+      return Math.sqrt(this.dot(this));
+    },
+    unit: function() {
+      return this.divide(this.length());
+    },
+    min: function() {
+      return Math.min(Math.min(this.x, this.y), this.z);
+    },
+    max: function() {
+      return Math.max(Math.max(this.x, this.y), this.z);
+    },
+    toAngles: function() {
+      return {
+        theta: Math.atan2(this.z, this.x),
+        phi: Math.asin(this.y / this.length())
+      };
+    },
+    angleTo: function(a) {
+      return Math.acos(this.dot(a) / (this.length() * a.length()));
+    },
+    toArray: function(n) {
+      return [this.x, this.y, this.z].slice(0, n || 3);
+    },
+    clone: function() {
+      return new Vector(this.x, this.y, this.z);
+    },
+    init: function(x, y, z) {
+      this.x = x; this.y = y; this.z = z;
+      return this;
+    }
+  };
+  
+  Vector.negative = function(a, b) {
+    b.x = -a.x; b.y = -a.y; b.z = -a.z;
+    return b;
+  };
+  Vector.add = function(a, b, c) {
+    if (b instanceof Vector) { c.x = a.x + b.x; c.y = a.y + b.y; c.z = a.z + b.z; }
+    else { c.x = a.x + b; c.y = a.y + b; c.z = a.z + b; }
+    return c;
+  };
+  Vector.subtract = function(a, b, c) {
+    if (b instanceof Vector) { c.x = a.x - b.x; c.y = a.y - b.y; c.z = a.z - b.z; }
+    else { c.x = a.x - b; c.y = a.y - b; c.z = a.z - b; }
+    return c;
+  };
+  Vector.multiply = function(a, b, c) {
+    if (b instanceof Vector) { c.x = a.x * b.x; c.y = a.y * b.y; c.z = a.z * b.z; }
+    else { c.x = a.x * b; c.y = a.y * b; c.z = a.z * b; }
+    return c;
+  };
+  Vector.divide = function(a, b, c) {
+    if (b instanceof Vector) { c.x = a.x / b.x; c.y = a.y / b.y; c.z = a.z / b.z; }
+    else { c.x = a.x / b; c.y = a.y / b; c.z = a.z / b; }
+    return c;
+  };
+  Vector.cross = function(a, b, c) {
+    c.x = a.y * b.z - a.z * b.y;
+    c.y = a.z * b.x - a.x * b.z;
+    c.z = a.x * b.y - a.y * b.x;
+    return c;
+  };
+  Vector.unit = function(a, b) {
+    var length = a.length();
+    b.x = a.x / length;
+    b.y = a.y / length;
+    b.z = a.z / length;
+    return b;
+  };
+  Vector.fromAngles = function(theta, phi) {
+    return new Vector(Math.cos(theta) * Math.cos(phi), Math.sin(phi), Math.sin(theta) * Math.cos(phi));
+  };
+  Vector.randomDirection = function() {
+    return Vector.fromAngles(Math.random() * Math.PI * 2, Math.asin(Math.random() * 2 - 1));
+  };
+  Vector.min = function(a, b) {
+    return new Vector(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.min(a.z, b.z));
+  };
+  Vector.max = function(a, b) {
+    return new Vector(Math.max(a.x, b.x), Math.max(a.y, b.y), Math.max(a.z, b.z));
+  };
+  Vector.lerp = function(a, b, fraction) {
+    return b.subtract(a).multiply(fraction).add(a);
+  };
+  Vector.fromArray = function(a) {
+    return new Vector(a[0], a[1], a[2]);
+  };
+  Vector.angleBetween = function(a, b) {
+    return a.angleTo(b);
+  };
+  

+ 4 - 2
smty/smty.html

@@ -37,7 +37,9 @@
 </script>
 
 <script src="./lib/tvSysBtnBind.v2.1.js"></script>
-
+<script src="./lib/tour.js"></script>
+<script src="./lib/tween.umd.js"></script>
+<script src="./lib/vector.js"></script>
 
 <body id="Jdoc">
 
@@ -109,7 +111,7 @@
         <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 src="js/smty.min.js"></script>
+        <script src="js/smty.js"></script>
     </div>
 
 

+ 1 - 4
smty/tip.html

@@ -102,7 +102,7 @@
             },
             onPress:function() {
                 var keyCode = this.event.keyCode;
-                // alert('tvSysBtnBind:'+keyCode+" - " + this.event.key)
+
                 switch (keyCode) {
                     case 37: // left
                     // reloadData();
@@ -119,9 +119,6 @@
 
                 const url = 'ybf.html?id='+pano_Id+'&backurl='+backurl
 
-                // document.getElementById('debug').innerHTML +="<br>" +url
-
-                // window.location.href = url
                 window.location.replace(url) 
         
             }

+ 3 - 10
smty/ybf.html

@@ -29,15 +29,6 @@
             
 }
 
-/*
-        .navigation{
-            display: flex;
-            flex-direction: column;
-            margin-left: 30px;
-            margin-top: 30px;
-        }
-        
-        */
 
         #debug{
             display: none;
@@ -131,7 +122,9 @@
 
     <div class="ctrlBtn"></div>
 
-    <script src="js/ybf.min.js"></script>
+    <script src="lib/tween.umd.js"></script>
+
+    <script src="js/ybf.js"></script>
 
     <script type="text/javaScript">
 

+ 3 - 1
yljq/index.html

@@ -115,7 +115,9 @@
 
     <div class="ctrlBtn"></div>
 
-    <script src="js/index.min.js"></script>
+    <script src="lib/tween.umd.js"></script>
+
+    <script src="js/index.js"></script>
 
     <script type="text/javaScript">
 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 381 - 0
yljq/js/index.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 1
yljq/js/index.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1674 - 0
yljq/js/ypano.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 1
yljq/js/ypano.min.js


+ 8 - 6
yljq/ypano.html

@@ -37,7 +37,8 @@
 </script>
 
 <script src="./lib/tvSysBtnBind.v2.1.js"></script>
-
+<script src="./lib/tour.js"></script>
+<script src="./lib/tween.umd.js"></script>
 
 <body id="Jdoc">
 
@@ -94,21 +95,22 @@
     
 
     <div class="ctrlBtn"></div>	
-    
 
-    <audio src="./audio/bg.mp3" autoplay loop type="audio/mpeg" id="bgAudio" > </audio>
+      <audio src="./audio/bg.mp3" autoplay loop type="audio/mpeg" id="bgAudio" > </audio>
+      <!-- <audio autoplay loop controls type="audio/mpeg" id="playAudio">
+        <source src="./audio/bg.mp3">
+    </audio> -->
 
 
     <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 src="js/ypano.min.js"></script>
+        <script src="js/ypano.js"></script>
     </div>
 
 
-    
-    
+  
 
 
 </body>