|
@@ -1,7 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
import * as THREE from "../../../libs/three.js/build/three.module.js";
|
|
import * as THREE from "../../../libs/three.js/build/three.module.js";
|
|
|
-import math from './math.js'
|
|
|
|
|
|
|
+import math from './math.js'
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
|
|
|
var Common = {
|
|
var Common = {
|
|
|
|
|
|
|
@@ -118,35 +120,34 @@ var Common = {
|
|
|
|
|
|
|
|
,
|
|
,
|
|
|
|
|
|
|
|
- CloneObject : function(copyObj, result, isSimpleCopy, simpleCopyList=[]) {
|
|
|
|
|
|
|
+ CloneObject : function (copyObj, isSimpleCopy, simpleCopyList = [], judgeSimpleCopyFun) {
|
|
|
//isSimpleCopy 只复制最外层
|
|
//isSimpleCopy 只复制最外层
|
|
|
- //复制json result的可能:普通数字或字符串、普通数组、复杂对象
|
|
|
|
|
-
|
|
|
|
|
- simpleCopyList.push(THREE.Object3D) //遇到simpleCopyList中的类直接使用不拷贝
|
|
|
|
|
|
|
+ //复制json result的可能:普通数字或字符串、普通数组、复杂对象
|
|
|
|
|
+ judgeSimpleCopyFun || (judgeSimpleCopyFun=()=>{})
|
|
|
|
|
|
|
|
- if(!copyObj || typeof copyObj == 'number' || typeof copyObj == 'string' || copyObj instanceof Function || simpleCopyList.some(className => copyObj instanceof className)){
|
|
|
|
|
- return copyObj
|
|
|
|
|
|
|
+ if (!copyObj || typeof copyObj == 'number' || typeof copyObj == 'string' ||copyObj.isObject3D || copyObj instanceof Function || simpleCopyList.some(className => copyObj instanceof className) || judgeSimpleCopyFun(copyObj)) {
|
|
|
|
|
+ return copyObj
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- result = result || {};
|
|
|
|
|
|
|
+
|
|
|
if (copyObj instanceof Array) {
|
|
if (copyObj instanceof Array) {
|
|
|
- return copyObj.map(e=>{
|
|
|
|
|
- return this.CloneObject(e)
|
|
|
|
|
- })
|
|
|
|
|
- }else{
|
|
|
|
|
- if(copyObj.clone instanceof Function ){ //解决一部分
|
|
|
|
|
|
|
+ return copyObj.map(e => {
|
|
|
|
|
+ return this.CloneObject(e, isSimpleCopy, simpleCopyList, judgeSimpleCopyFun)
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (copyObj.clone instanceof Function) {
|
|
|
|
|
+ //解决一部分
|
|
|
return copyObj.clone()
|
|
return copyObj.clone()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ let result = {}
|
|
|
for (var key in copyObj) {
|
|
for (var key in copyObj) {
|
|
|
- if (copyObj[key] instanceof Object && !isSimpleCopy)
|
|
|
|
|
- result[key] = this.CloneObject(copyObj[key]);
|
|
|
|
|
- else
|
|
|
|
|
- result[key] = copyObj[key];
|
|
|
|
|
|
|
+ if (copyObj[key] instanceof Object && !isSimpleCopy ) result[key] = this.CloneObject(copyObj[key], isSimpleCopy, simpleCopyList, judgeSimpleCopyFun)
|
|
|
|
|
+ else result[key] = copyObj[key]
|
|
|
//如果是函数类同基本数据,即复制引用
|
|
//如果是函数类同基本数据,即复制引用
|
|
|
}
|
|
}
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return result
|
|
|
|
|
+ }
|
|
|
,
|
|
,
|
|
|
CloneClassObject :function(copyObj, {ignoreList=[],simpleCopyList=[]}={}){//复杂类对象
|
|
CloneClassObject :function(copyObj, {ignoreList=[],simpleCopyList=[]}={}){//复杂类对象
|
|
|
var newobj = new copyObj.constructor();
|
|
var newobj = new copyObj.constructor();
|
|
@@ -166,7 +167,7 @@ var Common = {
|
|
|
}else if(simpleCopyList.includes(i)){
|
|
}else if(simpleCopyList.includes(i)){
|
|
|
targetObj[i] = copyObj[i]
|
|
targetObj[i] = copyObj[i]
|
|
|
}else{
|
|
}else{
|
|
|
- targetObj[i] = this.CloneObject(copyObj[i], null, false, simpleCopyList )
|
|
|
|
|
|
|
+ targetObj[i] = this.CloneObject(copyObj[i], false, simpleCopyList )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -225,12 +226,6 @@ var Common = {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
,
|
|
,
|
|
|
- replaceAll : function (str, f, e) {
|
|
|
|
|
- //f全部替换成e
|
|
|
|
|
- var reg = new RegExp(f, "g"); //创建正则RegExp对象
|
|
|
|
|
- return str.replace(reg, e);
|
|
|
|
|
- }
|
|
|
|
|
- ,
|
|
|
|
|
downloadFile : function(data, filename, cb) {
|
|
downloadFile : function(data, filename, cb) {
|
|
|
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
|
|
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
|
|
|
save_link.href = data;
|
|
save_link.href = data;
|
|
@@ -240,15 +235,59 @@ var Common = {
|
|
|
save_link.dispatchEvent(event);
|
|
save_link.dispatchEvent(event);
|
|
|
cb && cb();
|
|
cb && cb();
|
|
|
},
|
|
},
|
|
|
|
|
+
|
|
|
|
|
+ replaceAll : function (str, f, e ) {
|
|
|
|
|
+ //f全部替换成e
|
|
|
|
|
+
|
|
|
|
|
+ if(str.replaceAll ) return str.replaceAll(f, e)
|
|
|
|
|
+ else{
|
|
|
|
|
+ let escapeRegExp = (string)=>{
|
|
|
|
|
+ return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return str.replace(new RegExp(escapeRegExp(f), 'g'), e);
|
|
|
|
|
+
|
|
|
|
|
+ /* var reg = new RegExp(f, "g"); //创建正则RegExp对象 这个没法转换'('
|
|
|
|
|
+ return str.replace(reg, e); //str.split(f).join(e); */
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
|
|
|
- dealURL(url){
|
|
|
|
|
- return this.replaceAll(url, "\\+", "%2B");// 浏览器似乎不支持访问带+的地址
|
|
|
|
|
|
|
+
|
|
|
|
|
+ cleanUrl(url){//斜杠处理 协议aaa://保留双斜杠,其余单斜杠
|
|
|
|
|
+ //分离协议和路径部分
|
|
|
|
|
+ const protocolMatch = url.match(/^(\w+:)\/{2,}/);
|
|
|
|
|
+
|
|
|
|
|
+ if (protocolMatch) {
|
|
|
|
|
+ const protocol = protocolMatch[1];
|
|
|
|
|
+ const path = url.slice(protocolMatch[0].length);
|
|
|
|
|
+ return protocol + '//' + path.replace(/\/+/g, '/');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return url.replace(/\/+/g, '/');
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ joinUrl(){//拼接地址。总是出现前后多个/造成双斜杠或者缺斜杠的问题,处理一下
|
|
|
|
|
+ return this.cleanUrl(Array.from(arguments).join('/'))
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ dealURL(url=''){
|
|
|
|
|
+ let urlNew = this.replaceAll(url, "+", "%2B"); //this.replaceAll(url, "\\+", "%2B");// 浏览器似乎不支持访问带+的地址
|
|
|
|
|
+
|
|
|
|
|
+ urlNew = this.replaceAll(urlNew, "/.//", "/") //去除双斜杠(/.//)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //urlNew = encodeURIComponent(url)
|
|
|
|
|
+
|
|
|
|
|
+ return urlNew
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
- getNameFromURL(url){
|
|
|
|
|
|
|
+ getNameFromURL(url, removePostfix){
|
|
|
|
|
+ if(!url)return ''
|
|
|
let get = (e)=>{
|
|
let get = (e)=>{
|
|
|
- return e.split('/').pop()
|
|
|
|
|
|
|
+ let a = e.split('/').pop()
|
|
|
|
|
+ if(removePostfix) a = a.split('.')[0]
|
|
|
|
|
+ return a
|
|
|
}
|
|
}
|
|
|
if(url instanceof Array){
|
|
if(url instanceof Array){
|
|
|
return url.map(e=>get(e))
|
|
return url.map(e=>get(e))
|
|
@@ -266,35 +305,31 @@ var Common = {
|
|
|
|
|
|
|
|
intervalTool:{ //延时update,防止卡顿
|
|
intervalTool:{ //延时update,防止卡顿
|
|
|
list:[],
|
|
list:[],
|
|
|
-
|
|
|
|
|
- /* isWaiting:function(name, func, delayTime ){
|
|
|
|
|
- let item = this.list.find(e=>e.name == name)
|
|
|
|
|
- if(!item){ //如果没有该项, 则加入循环
|
|
|
|
|
- let ifContinue = func()
|
|
|
|
|
- item = {name}
|
|
|
|
|
- this.list.push(item);
|
|
|
|
|
- setTimeout(()=>{
|
|
|
|
|
- var a = this.list.indexOf(item);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /* isWaiting:function(name, func, delayTime){
|
|
|
|
|
+ if(!this.list.includes(name)){ //如果没有该项, 则开始判断
|
|
|
|
|
+ var needWait = func(); //触发了改变,则等待一段时间后再自动判断
|
|
|
|
|
+ if(needWait){
|
|
|
|
|
+ this.list.push(name);
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ var a = this.list.indexOf(name);
|
|
|
this.list.splice(a,1);
|
|
this.list.splice(a,1);
|
|
|
- if(item.requestUpdate || ifContinue ) this.isWaiting(name, func, delayTime) //循环
|
|
|
|
|
|
|
+ this.isWaiting(name, func, delayTime) //循环
|
|
|
},delayTime)
|
|
},delayTime)
|
|
|
-
|
|
|
|
|
- }else{//如果有该项,说明现在请求下一次继续更新
|
|
|
|
|
- //if(delayTime == 0){//想立刻更新一次
|
|
|
|
|
- // func()
|
|
|
|
|
- //}else{
|
|
|
|
|
- item.requestUpdate = true
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}, */
|
|
}, */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
isWaiting:function(name, func, delayTime/* , autoCycle */){
|
|
isWaiting:function(name, func, delayTime/* , autoCycle */){
|
|
|
let item = this.list.find(e=>e.name == name)
|
|
let item = this.list.find(e=>e.name == name)
|
|
|
if(!item){ //如果没有该项, 则加入循环
|
|
if(!item){ //如果没有该项, 则加入循环
|
|
|
let ifContinue = func()
|
|
let ifContinue = func()
|
|
|
item = {name, func, delayTime}
|
|
item = {name, func, delayTime}
|
|
|
|
|
+ /* if(name == 'processPriorityQueue'){
|
|
|
|
|
+ console.log('isWaiting', delayTime)
|
|
|
|
|
+ } */
|
|
|
this.list.push(item);
|
|
this.list.push(item);
|
|
|
setTimeout(()=>{
|
|
setTimeout(()=>{
|
|
|
var a = this.list.indexOf(item);
|
|
var a = this.list.indexOf(item);
|
|
@@ -310,24 +345,64 @@ var Common = {
|
|
|
//更新属性
|
|
//更新属性
|
|
|
item.func = func
|
|
item.func = func
|
|
|
item.delayTime = delayTime
|
|
item.delayTime = delayTime
|
|
|
- item.requestUpdate = true
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
|
|
+ item.requestUpdate = true
|
|
|
|
|
+ //}
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+ ,
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ waitTool:{//定时器,在等待的这段时间内如果又触发则重新计时
|
|
|
|
|
+ list:[],
|
|
|
|
|
+
|
|
|
|
|
+ wait(name, func, time){
|
|
|
|
|
+ let item = this.list.find(e=>e.name == name)
|
|
|
|
|
+
|
|
|
|
|
+ let timer = setTimeout(()=>{
|
|
|
|
|
+ func()
|
|
|
|
|
+ let index = this.list.indexOf(item)
|
|
|
|
|
+ this.list.splice(index, 1)
|
|
|
|
|
+ }, time)
|
|
|
|
|
+ if(item){
|
|
|
|
|
+ clearTimeout(item.timer)
|
|
|
|
|
+ }else{
|
|
|
|
|
+ item = {name}
|
|
|
|
|
+ this.list.push(item)
|
|
|
}
|
|
}
|
|
|
|
|
+ item.timer = timer
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ cancel(name){
|
|
|
|
|
+ let index = this.list.findIndex(e=>e.name == name)
|
|
|
|
|
+ index>-1 && this.list.splice(index, 1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
,
|
|
,
|
|
|
- pushToGroupAuto : function(items, groups, recognizeFunction){//自动分组。 items是将分到一起的组合。items.length = 1 or 2.
|
|
|
|
|
|
|
+ pushToGroupAuto : function(items, groups, recognizeFunction, recognizeGroup){//自动分组。 items是将分到一起的组合。items.length = 1 or 2.
|
|
|
|
|
|
|
|
recognizeFunction = recognizeFunction || function(){}
|
|
recognizeFunction = recognizeFunction || function(){}
|
|
|
|
|
|
|
|
- var atGroups = groups.filter(group=>group.find(
|
|
|
|
|
- item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
|
|
|
|
|
|
|
|
|
|
- ))
|
|
|
|
|
|
|
+ if(recognizeGroup){ //有更复杂的识别处理,直接传递整个组
|
|
|
|
|
+ var atGroups = groups.filter(group=>recognizeGroup(group, items))
|
|
|
|
|
+
|
|
|
|
|
+ }else{
|
|
|
|
|
+ var atGroups = groups.filter(group=>group.find(
|
|
|
|
|
+ item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
|
|
|
|
|
+ ))
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
if(atGroups.length){//在不同组
|
|
if(atGroups.length){//在不同组
|
|
|
//因为items是一组的,所以先都放入组1
|
|
//因为items是一组的,所以先都放入组1
|
|
|
items.forEach(item=> {if(!atGroups[0].includes(item)) atGroups[0].push(item);})
|
|
items.forEach(item=> {if(!atGroups[0].includes(item)) atGroups[0].push(item);})
|
|
@@ -347,30 +422,58 @@ var Common = {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- getBestCount : function(name, minCount=1,maxCount=6, durBound1 = 1.2, durBound2 = 10, ifLog){
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ getBestCount : (function(){
|
|
|
|
|
+ let lastCount = {}
|
|
|
|
|
+ return function(name, minCount=1,maxCount=6, durBound1 = 1.2, durBound2 = 10, ifLog, maxHistory){
|
|
|
|
|
+ let timeStamp = performance.getEntriesByName("loop-start");
|
|
|
|
|
+ let count
|
|
|
|
|
+ if(timeStamp.length){
|
|
|
|
|
+ let dur = performance.now() - timeStamp[timeStamp.length-1].startTime; //dur在iphoneX中静止有7,pc是2
|
|
|
|
|
+
|
|
|
|
|
+ count = Math.round(math.linearClamp(dur, [durBound1,durBound2], [maxCount, minCount]))
|
|
|
|
|
+
|
|
|
|
|
+ if (maxHistory) {
|
|
|
|
|
+ if (!lastCount[name]) lastCount[name] = []
|
|
|
|
|
+ if (count == 0 && lastCount[name].length > maxHistory - 1 && !lastCount[name].some(e => e > 0)) {
|
|
|
|
|
+ count = 1
|
|
|
|
|
+ }
|
|
|
|
|
+ lastCount[name].push(count)
|
|
|
|
|
+ if (lastCount[name].length > maxHistory) lastCount[name].splice(0, 1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if(ifLog){//注意,console.log本身用时挺高, 降4倍时可能占用0.5毫秒
|
|
|
|
|
+ name && count && console.log(name, count , ' ,dur:', dur.toFixed(3))
|
|
|
|
|
+ }
|
|
|
|
|
+ }else{
|
|
|
|
|
+ count = maxCount // ?
|
|
|
|
|
+ }
|
|
|
|
|
+ //主要在手机端有效果。
|
|
|
|
|
+ return count
|
|
|
|
|
+ }
|
|
|
|
|
+ })(),
|
|
|
|
|
+
|
|
|
|
|
+ getBestCountFPS(name, ifLog, minCount=1, maxCount=6, minFps = 10, maxFps = 60, minPanoCount = 200, maxPanoCount = 1000 ){
|
|
|
|
|
+
|
|
|
|
|
+ let fps = Potree.fps
|
|
|
|
|
+
|
|
|
|
|
+ let count = math.linearClamp(fps, [minFps, maxFps], [minCount, maxCount])
|
|
|
|
|
+
|
|
|
|
|
+ let count2 = math.linearClamp(viewer.images360.panos.length, [minPanoCount, maxPanoCount], [minCount, maxCount])
|
|
|
|
|
+ count = (count + count2)/2
|
|
|
|
|
|
|
|
- let timeStamp = performance.getEntriesByName("loop-start");
|
|
|
|
|
- let count
|
|
|
|
|
- if(timeStamp.length){
|
|
|
|
|
- let dur = performance.now() - timeStamp[timeStamp.length-1].startTime; //dur在iphoneX中静止有7,pc是2
|
|
|
|
|
-
|
|
|
|
|
- count = Math.round(math.linearClamp(dur, durBound1,durBound2, maxCount, minCount))
|
|
|
|
|
-
|
|
|
|
|
- if(ifLog){//注意,console.log本身用时挺高, 降4倍时可能占用0.5毫秒
|
|
|
|
|
- name && count && console.log(name, count , ' ,dur:', dur.toFixed(3))
|
|
|
|
|
- }
|
|
|
|
|
- }else{
|
|
|
|
|
- count = maxCount // ?
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ count = Math.round(count)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if(ifLog){
|
|
|
|
|
+ name && count && console.log(name, count , ' ,fps:', fps.toFixed(3))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return count
|
|
|
|
|
|
|
|
- //主要在手机端有效果。
|
|
|
|
|
- return count
|
|
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
batchHandling : {//分批处理
|
|
batchHandling : {//分批处理
|
|
|
|
|
|
|
@@ -436,6 +539,20 @@ var Common = {
|
|
|
|
|
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ getRootWindow(){//获取包含Potree的根window
|
|
|
|
|
+ let win = window
|
|
|
|
|
+ try{
|
|
|
|
|
+ while(win.parent!=win && win.parent.Potree){
|
|
|
|
|
+ win = win.parent
|
|
|
|
|
+ }
|
|
|
|
|
+ if(window != win)return win
|
|
|
|
|
+ }catch(e){
|
|
|
|
|
+ //console.log(e) //可能跨域,从而win.parent.Potree报错
|
|
|
|
|
+ console.log('getRootWindow 跨域')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
|
|
|
watch: function(object, propName, initialValue){ //监听某个属性的变化
|
|
watch: function(object, propName, initialValue){ //监听某个属性的变化
|
|
|
let v = initialValue
|
|
let v = initialValue
|
|
@@ -450,8 +567,189 @@ var Common = {
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ imgAddLabel : function (img, labelImg, labelInfo = {}) {
|
|
|
|
|
+ //图上加另一张小图,用于添加水印
|
|
|
|
|
+ let canvas
|
|
|
|
|
+ if(img instanceof Image){
|
|
|
|
|
+ canvas = document.createElement('canvas')
|
|
|
|
|
+ }else{
|
|
|
|
|
+ canvas = img
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let context = canvas.getContext('2d')
|
|
|
|
|
+ let marginLeft = labelInfo.bgMargin && labelInfo.bgMargin.left || 0
|
|
|
|
|
+ let marginRight = labelInfo.bgMargin && labelInfo.bgMargin.right || 0
|
|
|
|
|
+ let marginTop = labelInfo.bgMargin && labelInfo.bgMargin.top || 0
|
|
|
|
|
+ let marginBottom = labelInfo.bgMargin && labelInfo.bgMargin.bottom || 0
|
|
|
|
|
+
|
|
|
|
|
+ if(img instanceof Image){//如果img是canvas,说明已绘制在canvas上了就不用绘制了
|
|
|
|
|
+ let width = img.width + marginLeft + marginRight
|
|
|
|
|
+ let height = img.height + marginTop + marginBottom
|
|
|
|
|
+ canvas.width = width
|
|
|
|
|
+ canvas.height = height
|
|
|
|
|
+ if(labelInfo.bgColor){
|
|
|
|
|
+ context.fillStyle = 'rgba(' + labelInfo.bgColor.r + ',' + labelInfo.bgColor.g + ',' + labelInfo.bgColor.b + ',' + labelInfo.bgColor.a + ')';
|
|
|
|
|
+ context.fillRect(0,0,width,height);
|
|
|
|
|
+ }
|
|
|
|
|
+ context.drawImage(img, marginLeft, marginTop, img.width, img.height)
|
|
|
|
|
+ }
|
|
|
|
|
+ let labelWidth = labelInfo.widthRatioToImg ? img.width * labelInfo.widthRatioToImg : labelImg.width //widthRatioToImg:label的width占img的width的比例
|
|
|
|
|
+ let labelHeight = (labelWidth * labelImg.height) / labelImg.width
|
|
|
|
|
+
|
|
|
|
|
+ if (labelInfo.leftRatioToImg == void 0 && labelInfo.rightRatioToImg != void 0) {
|
|
|
|
|
+ labelInfo.leftRatioToImg = 1 - labelInfo.rightRatioToImg - (labelInfo.widthRatioToImg || labelImg.width / img.width)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (labelInfo.topRatioToImg == void 0 && labelInfo.bottomRatioToImg != void 0) {
|
|
|
|
|
+ labelInfo.topRatioToImg = 1 - labelInfo.bottomRatioToImg - labelHeight / img.height
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let labelLeft = img.width * labelInfo.leftRatioToImg + marginLeft //leftRatioToImg:label的left占img的width的比例
|
|
|
|
|
+ let labelTop = img.height * labelInfo.topRatioToImg + marginTop //topRatioToImg:label的top占img的height的比例
|
|
|
|
|
+
|
|
|
|
|
+ context.globalAlpha = labelInfo.opacity != void 0 ? labelInfo.opacity : 1
|
|
|
|
|
+ context.drawImage(labelImg, labelLeft, labelTop, labelWidth, labelHeight)
|
|
|
|
|
+
|
|
|
|
|
+ if(labelInfo.outputCanvas){
|
|
|
|
|
+ return canvas
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var dataUrl = canvas.toDataURL('image/png', labelInfo.compressRatio)
|
|
|
|
|
+ //Common.downloadFile(dataUrl, 'screenshot.png')
|
|
|
|
|
+ context.clearRect(0,0,canvas.width,canvas.height)
|
|
|
|
|
+ return dataUrl
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ mobileAutoPlay(media, playFun){//移动端。不这么写video不会播放 . (2022.11.29: 可为何加了Hot.updateHots之后又会自动播了?https有关?
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if(this.autoPlayList.includes(media))return
|
|
|
|
|
+ this.autoPlayList.push(media)
|
|
|
|
|
+ viewer.addEventListener
|
|
|
|
|
+ let events = ['global_touchstart','global_mousedown']
|
|
|
|
|
+
|
|
|
|
|
+ let fun = ()=>{
|
|
|
|
|
+ let index = this.autoPlayList.indexOf(media)
|
|
|
|
|
+ if(index>-1){
|
|
|
|
|
+
|
|
|
|
|
+ console.log( 'try autoplay '+ media.src)
|
|
|
|
|
+ playFun()
|
|
|
|
|
+ this.autoPlayList.splice(index,1)
|
|
|
|
|
+ events.forEach((eventName)=>{
|
|
|
|
|
+ viewer.removeEventListener(eventName,fun)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ events.forEach((eventName)=>{
|
|
|
|
|
+ viewer.addEventListener(eventName,fun)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ /* changeShaderToWebgl2(vs, fs, matType, otherReplaces=[]){//部分shader要根据webgl版本作更改
|
|
|
|
|
+ if(!Potree.settings.isWebgl2)return {vs, fs}
|
|
|
|
|
+ let turnTo300 = matType != 'ShaderMaterial' && (vs.includes('gl_FragDepthEXT') || fs.includes('gl_FragDepthEXT') )
|
|
|
|
|
+ let addV300 = turnTo300 && matType != 'RawShaderMaterial' // RawShaderMaterial直接material.glslVersion = '300 es' 以加在define之前
|
|
|
|
|
+ let change = (shader, shaderType)=>{
|
|
|
|
|
+ let newShader = shader
|
|
|
|
|
+
|
|
|
|
|
+ if(turnTo300){ //非shaderMaterial需要手动改为300 es的写法
|
|
|
|
|
+ addV300 && (newShader = '#version 300 es \n' + newShader) //需要加 #version 300 es。 three.js自带的渲染会自动加所以不用
|
|
|
|
|
+ newShader = newShader.replaceAll('varying ', shaderType == 'vs' ? 'out ' : 'in ')
|
|
|
|
|
+ newShader = newShader.replaceAll('attribute ', 'in ')
|
|
|
|
|
+ if(shaderType == 'fs'){
|
|
|
|
|
+ newShader = newShader.replaceAll('gl_FragColor', 'fragColor')
|
|
|
|
|
+ newShader = newShader.replace('void main', 'out vec4 fragColor;\n void main' )//在void main前加入这个声明
|
|
|
|
|
+ }
|
|
|
|
|
+ newShader = newShader.replaceAll('gl_FragDepthEXT','gl_FragDepth')
|
|
|
|
|
+
|
|
|
|
|
+ newShader = newShader.replaceAll('texture2D','texture')
|
|
|
|
|
+ newShader = newShader.replaceAll('textureCube','texture')
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ newShader = newShader.replace('#extension GL_EXT_frag_depth : enable','')
|
|
|
|
|
+ newShader = newShader.replaceAll('defined(GL_EXT_frag_depth) &&','')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ otherReplaces.forEach(({oldStr,newStr})=>{
|
|
|
|
|
+ newShader = newShader.replaceAll(oldStr,newStr)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return newShader
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ vs = change(vs,'vs')
|
|
|
|
|
+ fs = change(fs,'fs')
|
|
|
|
|
+
|
|
|
|
|
+ //console.log('成功替换为webgl2' )
|
|
|
|
|
+ return {vs,fs}
|
|
|
|
|
+ }//three.js的shaderMaterial也有替换功能,搜 '#define gl_FragDepthEXT gl_FragDepth',
|
|
|
|
|
+ */
|
|
|
|
|
+ changeShaderToWebgl2(vs, fs, matType, otherReplaces=[]){//部分shader要根据webgl版本作更改
|
|
|
|
|
+ if(!Potree.settings.isWebgl2)return {vs, fs}
|
|
|
|
|
+ let turnTo300 = matType != 'ShaderMaterial' && (vs.includes('gl_FragDepthEXT') || fs.includes('gl_FragDepthEXT') )
|
|
|
|
|
+ let addV300 = turnTo300 && matType != 'RawShaderMaterial' // RawShaderMaterial直接material.glslVersion = '300 es' 以加在define之前
|
|
|
|
|
+ let change = (shader, shaderType)=>{
|
|
|
|
|
+ let newShader = shader
|
|
|
|
|
+
|
|
|
|
|
+ if(turnTo300){ //非shaderMaterial需要手动改为300 es的写法
|
|
|
|
|
+ addV300 && (newShader = '#version 300 es \n' + newShader) //需要加 #version 300 es。 three.js自带的渲染会自动加所以不用
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'varying ', shaderType == 'vs' ? 'out ' : 'in ')
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'attribute ', 'in ')
|
|
|
|
|
+ if(shaderType == 'fs'){
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'gl_FragColor', 'fragColor')
|
|
|
|
|
+ newShader = newShader.replace('void main', 'out vec4 fragColor;\n void main' )//在void main前加入这个声明
|
|
|
|
|
+ }
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'gl_FragDepthEXT','gl_FragDepth')
|
|
|
|
|
+
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'texture2D','texture')
|
|
|
|
|
+ newShader = this.replaceAll(newShader, 'textureCube','texture')
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ newShader = newShader.replace('#extension GL_EXT_frag_depth : enable','')
|
|
|
|
|
+ newShader = this.replaceAll(newShader,'defined(GL_EXT_frag_depth) &&','')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ otherReplaces.forEach(({oldStr,newStr})=>{
|
|
|
|
|
+ newShader = this.replaceAll(newShader, oldStr, newStr)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return newShader
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ vs = change(vs,'vs')
|
|
|
|
|
+ fs = change(fs,'fs')
|
|
|
|
|
+
|
|
|
|
|
+ //console.log('成功替换为webgl2' )
|
|
|
|
|
+ return {vs,fs}
|
|
|
|
|
+ },//three.js的shaderMaterial也有替换功能,搜 '#define gl_FragDepthEXT gl_FragDepth',
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ //hsv感觉比hsl好一些,更能保持颜色本身不变。 色调(H),饱和度(S),明度(V/B)。
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ getHSV(color, prop={} ){
|
|
|
|
|
+ let c = new THREE.Color()
|
|
|
|
|
+ let hsv = c.set(color).getHSV()
|
|
|
|
|
+ if(prop.add){
|
|
|
|
|
+ for(let i in prop.add) hsv[i] += prop.add[i]
|
|
|
|
|
+ }else{
|
|
|
|
|
+ hsv = Object.assign(hsv, prop)
|
|
|
|
|
+ }
|
|
|
|
|
+ let {h, s, v} = hsv
|
|
|
|
|
+ return c.setHSV(h, s, v) //setHSV(hsb.h, hsb.s, 100)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+//let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Potree.Common = Common
|
|
Potree.Common = Common
|