var confirmSnap = $(".confirmSnap.innerBtn");
var snapshotGui = $(".snapshotGui.overlayGui");
var _musicMaxWeight = 8
//M
var _hotNum = 0
function reData(data, type) {
return JSON.stringify(data) == type ? null : data
}
let strictInputNum = function (e, precision, min = 0, max) {//precision:保留小数位数
var value = e.target.value.trim();
var lastOne = value[value.length - 1];
var preContent = value.substr(0, value.length - 1)
var hasPoint = precision > 0 && lastOne == '.';
var a = Math.pow(10, precision)
value = parseFloat(value) || 0;
if (isNaN(value)) {
e.target.value = preContent //还原
return
}
e.target.value = Math.max(min, parseInt(value * a) / a)
hasPoint && (e.target.value += '.')//补小数点
}
//新编辑界面
var EditTools = function (n) {
//main2018 里面的主要对象
this.n = n;
//当前状态
this.atPanel = null;
//场景信息
this.sceneInformation = new SceneInformation();
//热点
this.hotpoint = new Hotpoint();
//导览
this.editGuide = new EditGuide();
//音乐
this.EditBGM = new EditBGM();
//初始化界面
//this.init();
this.data = {}
this.editLabel = new EditLabel();
}
EditTools.prototype.loadDone = function (name, data) {
this.data[name] = data
if ('data' in this.data && 'data2' in this.data) {
this.init();
}
}
EditTools.prototype.init = function () {
this.hotpoint.init(/* this.n */);
var that = this;
this.initSaveAll();
this.active();
if (player.mode != 'panorama') {
$(".toolLeft li[data-name=panoVisible]").addClass('unable')
player.once("pano.chosen", () => {
$(".toolLeft li[data-name=panoVisible]").removeClass('unable')
})
}
//创建导览
that.EditBGM.init(this.data.data);
that.sceneInformation.init(this.data.data, this.data.data2)
// fyz 初始化导览需要两部分数据, 其中data2为data.js中的数据
that.editGuide.init(this.data.data, this.data.data2);
that.editLabel.init()
$("body").on("click", function () {
$(".DelConfirm").removeClass("active");
})
player.on("mode.changing", (currentMode, mode, pano) => { //起飞
if (this.atPanel != "screen" && !editTool.hotpoint.gettingCameraData) return
if (currentMode == "panorama") confirmSnap.addClass("unable")
})
player.on("flying.ended", (/* toPos, fromPos, pano */) => { //飞结束
if (this.atPanel != "screen" && !editTool.hotpoint.gettingCameraData) return
if (player.mode == "panorama") confirmSnap.removeClass("unable")
})
/* $(" .MenuOptions li").on("click", (e)=>{
var $elem = $(e.target);
$elem.closest('.MenuOptions').find('li').removeClass("chosen");
$elem.addClass("chosen");
}) */
//fyz 拖拽以改变顺序
{
let tourListNode = $("#tourList>ul")[0];
let tourItemListNode = $("#tourItemList>ul")[0];
let callback = function (ul) {
reIndexTourList(ul)
}
//导览拖拽
setDraggable({ ul: tourListNode, dragItemClassName: ['guideItem', 'listItem'], callback })
setDraggable({ ul: tourItemListNode, dragItemClassName: ['guideItem'], callback })
//热点媒体拖拽
setDraggable({ ul: $('#hotpointDetail [name="video"] .list')[0], dragItemClassName: ['mediaItem'] })
setDraggable({ ul: $('#hotpointDetail [name="photo"] .list')[0], dragItemClassName: ['mediaItem'] })
//热点列表拖拽
setDraggable({ ul: $('.toolRight .spotList')[0], dragItemClassName: ['listItem'] })
//roomLabel列表拖拽
setDraggable({ ul: $('.toolRight .roomLabels [name="list"]>ul')[0], dragItemClassName: ['listItem'] })
}
$(".toolRight .panoVisible [name=autoCompute]").on('click', () => {
VisiSet.resetPanosVisiByModel()
})
//平面图方向固定
this.fpAngleOptions = new MenuOptions({
dom: $(".toolRight .information [data-name=floorPlanAngle] .MenuOptions"),
uiCallBack: (o) => {
var name = o.name == void 0 ? o.$li.attr('index') : o.name
_settings.floorPlanAngle = parseFloat(name) * Math.PI / 2 //设置好方向 (0是无效的,将不设置)
if (name != 0 && player.ready) {
if (player.mode != 'floorplan' && player.modeTran.split('-') != 'floorplan') {
player.flyToMode('floorplan')
} else {
player.flyToMode('floorplan', () => {
player.cameraControls.controls.floorplan.rotateToAngle(_settings.floorPlanAngle)
})
}
}
},
callbackWhenChose: (o) => {
var name = o.$li.attr('index')
}
})
this.fpAngleOptions.updateChoseAtUI({ name: Math.round(_settings.floorPlanAngle / (Math.PI / 2)) })
}
//点击的时候激活状态
EditTools.prototype.active = function () {
var that = this;
$('.toolBottom .toolLeft li').click(function () {
var name = $(this).data("name");
$('.toolLeft li[data-name=' + name + ']').addClass("active").siblings().removeClass("active");
$('.toolRight .' + name).removeClass("hide").siblings().addClass("hide");
if (name == that.atPanel)
return;
console.log(`atPanel ${that.atPanel} name ${name}`)
switch (that.atPanel) {
//退出
case "panoVisible":
VisiSet.finishSetPanoVisible()
break;
case "panoLog":
VisiSet.finishSetPanoLog()
break;
case "screen":
confirmSnap.addClass("hide").removeClass("unable");
snapshotGui.hide();
break;
/* case "overlay":
EditOverlay.leave()
break; */
case "hotpoint":
$("#hotpointDetail").hasClass("atRight") || $("#hotpointDetail a.close").click();
VisiSet.finishSetTagVisible()
that.hotpoint.wireframeModel.visible = false
break;
case 'roomLabels':
that.editLabel.leave()
break;
}
switch (name) {
case "hotpoint":
that.hotpoint.wireframeModel.visible = that.hotpoint.wireframeModel.shouldShow
break;
case "panoVisible":
$(".toolLeft").addClass("unable")
VisiSet.enterSet(VisiSet.beginSetPanoVisible.bind(VisiSet))
break;
case "panoLog":
$(".toolLeft").addClass("unable")
VisiSet.enterSet(VisiSet.beginSetPanoLog.bind(VisiSet))
break;
case "screen":
confirmSnap.removeClass("hide");
$('#camera-start').text("点此设置为初始画面")
snapshotGui.show();
if (player.mode != "panorama")
confirmSnap.addClass("unable")
break;
/* case "overlay":
EditOverlay.enter()
break; */
case 'snapTour':
that.editGuide.scroller.tourBlackSpeed.InitOffset()
that.editGuide.scroller.tourWalkSpeed.InitOffset()
break;
case 'roomLabels':
that.editLabel.enter()
break;
}
that.atPanel = name;
/* if(name != "hotpoint"){
$("#hotpointDetail").hasClass("atRight") || $("#hotpointDetail a.close").click()
} */
})
//滚动阻止事件
$(".toolRight div.content").on("mousewheel", function (event) {
event.stopPropagation()
});
// 输入框阻止事件
$('.toolRight').on('keydown', function (ev) {
ev.stopPropagation();
})
//加空格和回车字符
$(".buttons[name='addSign'] button").on('click', function (e) {
let forAttr = $(this).parent().attr('for')
let textarea = forAttr ? $('#' + forAttr) : $(this).parent().parent().find('textarea')
let sign = $(this).attr('name') == 'space' ? ' ' : '
'
var v = textarea.val();
textarea.val(v + sign)
})
}
//保存按钮
EditTools.prototype.initSaveAll = function () {
var that = this;
$('#save').on('click', function () {
$(".edit-loading").removeClass("hide");
var $shareImages = $(".information .edit-fun-images a.result");
new Promise(function (resolve, reject) {//分享图
upload($shareImages, 'images', resolve)
}).then(function (imgUrls) {
//导览的数据
var guides = that.editGuide.getSavingInfo()/* Array.from($('.tourFolderList ul li')).map(function(dom) {
return dom.data
}) */
let tourRotTime = parseFloat($('.toolRight .snapTour [name="rotTime"] input').val())
isNaN(tourRotTime) && (tourRotTime = '')
var info = {
name: $('#pjtName').val(),
summary: $('#info-summary').val(),
weixinDesc: $('#weixin-summary').val(),
shareImgUrl: imgUrls[0] || '',
backgroundMusic: that.EditBGM.musicBox.getSrc() || '',
bgName: that.EditBGM.musicBox.getName(),
hoticon: JSON.parse($(".hotStyle-item li.active").attr("data-val")),
camera_start: $(".screen .shotImg.innerBtn")[0].cameraData,
loadlogo: $("#loadlogo").is(':checked'),
special: $("#g_specialScene").is(':checked'),
vision_version: $("#twoData").is(':checked') ? "1.1.562.17209" : false,
roomLabels: that.editLabel.getSavingInfo(),
/************************************** 方奕卓 场景可配置项 ******************************************/
hotImageScale: $("#hotImgScale").is(':checked'),
// 热点图片可放大
autoAdjustHotScale: $("#autoAdjustHotScale").is(':checked'),
hideFloorMarker: $("#hideFloorMarker").is(':checked'),
// 地面标记
hideMouseMarker: $("#hideMouseMarker").is(':checked'),
showingLabels: $("#showingLabels").is(':checked'),
// 鼠标标记
floorMarkerColor: $('#floorMarkerColor').val(),
// 地面/导览标志颜色
mouseMarkerColor: $('#mouseMarkerColor').val(),
// 鼠标标志颜色
momentTour: $('#tourSwitch input').is(':checked') ? 'black' : 'walk',
tourBlackSpeed: that.editGuide.scroller.tourBlackSpeed.value,
tourWalkSpeed: that.editGuide.scroller.tourWalkSpeed.value,
tourRotTime,
momentTourBlackNewType: $('#newBlack').is(':checked'),
showHotListSta: $('#hotListSwitch').is(':checked'),
// 开启热点列表
hotIconScale: DATA.hotIconScale,
// 热点缩放
supportsVR: $('#VRSwitch input').is(':checked'),
// 开启VR功能
/**************** 陈志广 小地图可配置项 *********** */
cadSignColor: $('#cadSignColor').val(),
cadBorderColor: $('#cadBorderColor').val(),
cadBorderWidth: $('#cad-size').val(),
showCad: $('input[name="show-cad"]').is(':checked'),
/**********/
floorPlanAngle: _settings.floorPlanAngle || 0 //俯视图旋转角
}
var data = {
sceneCode: number,
hots: reData(that.hotpoint.getSavingInfo(), '{}'),
//tourAudio: reData(that.editGuide.tourAudio,'{}'),//for 旧版
name: number,
guides: reData(guides, '[]'),
info: info,
}
console.log(data)
$.ajax({
method: 'POST',
headers: {
'Content-Type': 'application/json',
token: token
},
dataType: 'json',
contentType: 'application/json',
url: '/api/cms/scene/edit',
data: JSON.stringify(data),
success: function (data) {
if (data.code === 0) {//成功
//manage.showInfo("保存成功")
location.reload()
} else if (data.code === 5001) {
alert('请重新登录')
window.location.href='/backstage/#/login'
localStorage.removeItem(TOKEN_KEY)
location.reload()
} else {
alert(`saveAll (url:${url}) code : ${data.code} \n${data.msg}`)
}
}
})
});
})
}
class EditLabel {
constructor() {
}
init() {
let reverse = player.model.roomLabels.slice(0).reverse()
reverse.forEach(e => this.addLebelCallback(e))
$('.toolRight .roomLabels .addBtn button').on('click', () => {//准备添加
if (this.editingLabel) {
this.setEditLabel(false, this.editingLabel)
}
this.setAddState(true)
})
$('.toolRight .roomLabels [name="title"] input').on('input', (e) => {//标题
this.editingLabel.setTitle(e.target.value)
this.editingLabel.$li.find('.title').text(e.target.value)
})
/* $('.toolRight .roomLabels [name="delete"] button').on('click',(e)=>{//删除
this.deleteLabel(this.editingLabel)
this.setEditLabel(false,this.editingLabel)
}) */
player.on('getIntersect', (intersect, consume) => {//添加
if (this.adding) {
var position = intersect.point.clone();
position.y += 0.5
//var floorIndex = player.model.allFloorsVisible ? null : player.model.currentFloor.floorIndex
var floorIndex = intersect.object.parent.parent.floorIndex
var label = new RoomLabel({ position, title: '', floorIndex })
player.model.roomLabels.push(label)
this.setAddState(false)
this.addLebelCallback(label)
this.setEditLabel(true, label) //开始编辑
this.adding = false
label.update()
consume(true)
}
})
//点击列表弹出按钮
$('.toolRight .roomLabels [name="list"]>ul').on("click", (e) => {
var target = $(e.target);
let li = searchParent(e.target, { className: 'listItem' }, 7);
if (!li) return;
let label = li.label
if (target.hasClass("del")) {
e.stopPropagation();
target.siblings(".DelConfirm").addClass("active");
} else {
if (target.hasClass("DelConfirm")) {
e.stopPropagation();
this.deleteLabel(label);
} else {
this.setEditLabel(true, label) //开始编辑
}
}
});
}
deleteLabel(label) {
let index = player.model.roomLabels.indexOf(label)
index > -1 && player.model.roomLabels.splice(index, 1)
label.dispose()
label.$li.remove()
if (this.editingLabel == label) {
this.setEditLabel(false, this.editingLabel)
}
}
addLebelCallback(label) {
this.addLebelEvent(label)
this.addToList(label)
}
addToList(label) {
var $li = $("
'))
div.addClass('slider')
if (o.unitStr) {
div.find(".BarTxt").append($('
' + o.unitStr + ''));
}
o.root.append(div);
this.line = $(".scrollBar", div);
this.knot = $(".scroll_Thumb", div);
o.noValue || (this.textArea = $(".scrollBarTxt", div));
this.track = $(".scroll_Track", div);
this.unitStr = o.unitStr;
//unitStr是单位字符串,比如角度的°。不能是数字
this.onchange = o.onchange;
this.percent = null;
this.dragStart = false;
this.offsetToBody = null;
this.getOffset();
this.checkError();
this.percent = this.getPercent();
o.noValue || this.displayValue();
this.moveKnot();
this.knotWidth = 0;
this.lineWidth = 0;
//this.waitValue;//等待要触发事件的值,防止崩溃
this.avoidCrash = o.avoidCrash;
this.realMax = !this.noValue ? o.realMax : null;
//如果传入realMax,代表可以通过输入数字修改最大值范围,最大值不可以超过realMax。
this.scrollUnit = (scope.max - scope.min) * 0.001;
if (this.precision != void 0) {
var prec = Math.pow(10, -this.precision);
this.scrollUnit < prec && (this.scrollUnit = prec);
} else {
//默认化为整数
this.scrollUnit < 1 && (this.scrollUnit = 1);
}
this.dragStartEvent = o.dragStartEvent;
this.line.on("mousedown touchstart", function (event) {
scope.dragStart = true;
scope.dragChange(event);
if (scope.dragStartEvent)
scope.dragStartEvent()
//if(o.avoidCrash && isMobile)scope.dealInterval();
});
!window.isMobile && this.line.on("mousewheel DOMMouseScroll wheel", function (event) {
event.preventDefault();
var v = event.originalEvent.deltaY > 0 ? -scope.scrollUnit : scope.scrollUnit;
scope.setValue(scope.value + v);
});
this.dragEndEvent = o.dragEndEvent;
var stop = function () {
if (scope.dragStart) {
scope.dragStart = false;
if (scope.dragEndEvent)
scope.dragEndEvent()
}
}
$(document).on("mouseup touchend", stop)
/* isMobile || */
$("#player").on("mouseup", stop)
var lastChangeTime = 0;
$(document).on("mousemove touchmove", function () {
if (scope.dragStart) {
/* if(isMobile && o.avoidCrash){
scope.lastDragEvent = event;
}else */
scope.dragChange(event);
}
})
o.noValue || this.textArea.on("change", function () {
var v = parseFloat(scope.textArea.val());
if (v != v)
//NaN
return;
scope.setValueFromOutside(v);
});
window.addEventListener("resize", () => {
if (this.line[0].clientWidth) {
this.getOffset()
this.moveKnot();
}
})
}
SlideBar.prototype.dealInterval = function () {
this.interval = setInterval(function () {
this.lastDragEvent && this.dragChange(this.lastDragEvent);
this.lastDragEvent = null
if (!this.dragStart)
clearInterval(this.interval)
}
.bind(this), 90)
}
SlideBar.prototype.changeLimit = function (o) {
if (o.min)
this.min = o.min;
if (o.max)
this.max = o.max;
}
SlideBar.prototype.getOffset = function () {
//为了检测鼠标位置需要获得相对body的offset
var left = this.line[0].offsetLeft;
var element = this.line[0];
while (element = element.offsetParent) {
left += element.offsetLeft;
}
this.offsetToBody = (left == 0) ? (this.offsetToBody || 0) : left;
//如果left为0,很可能是它不可见,那么最好使用旧的offsetToBody
}
SlideBar.prototype.InitOffset = function () {
//如果一开始scroller没有显示,要在显示时获取一下offset
this.getOffset();
this.getWidth();
this.moveKnot();
}
SlideBar.prototype.checkError = function () {
if (this.min >= this.max) {
console.log("scrollbar值有误 " + name);
return;
}
}
SlideBar.prototype.getPercent = function () {
return (this.value - this.min) / (this.max - this.min);
}
SlideBar.prototype.displayValue = function (value) {
//this.textArea.val(this.value + (this.unitStr ? " " + this.unitStr : ""));
if (value != void 0)
this.value = value;
this.textArea.val(this.value)
}
SlideBar.prototype.getWidth = function () {
this.knotWidth = this.knot.width();
this.lineWidth = this.line.width() - this.knotWidth
}
SlideBar.prototype.moveKnot = function () {
//this.getWidth();
var width = this.percent * this.lineWidth;
this.knot.css('left', width + "px")
if (this.track)
this.track.css('width', (width + this.knotWidth / 2) + "px")
}
SlideBar.prototype.bind = function (f) {
this.onchange = f;
}
SlideBar.prototype.setValue = function (v, noEvent, changeMax) {
//设置数值并改变knot位置 noEvent为true的话就可以不触发回调函数,仅仅改变显示
//if(this.value==v)return; //因为换选材质需要执行后面onchange才会带动preview的改变,所以这里一样还是执行,而拉动滑动条的部分值不变就不执行
if (this.precision != void 0) {
this.value = parseFloat(v.toFixed(this.precision))
} else {
//默认化为整数
this.value = Math.round(v);
}
this.value = THREE.Math.clamp(this.value, this.min, this.max)
if (changeMax && this.realMax != void 0) {
if (this.value > this.oriMax) {
this.value = Math.min(this.value, this.realMax);
this.changeLimit({
max: this.value
})
} else {
this.changeLimit({
max: this.oriMax
})
}
}
this.percent = this.getPercent();
var makeit = true;
if (this.onchange && !noEvent) {
var result = this.onchange(this.value);
//如果执行的函数不允许这个值,就不能变
if (result === false) {
makeit = false;
}
}
if (makeit) {
this.moveKnot();
//console.log("SlideBarV-"+this.name + " : "+this.value)
this.noValue || this.displayValue();
}
}
SlideBar.prototype.dragChange = function (event) {
//拖动时触发 计算数值
//this.getWidth();
//if(!this.offsetToBody || isNaN(this.offsetToBody)this.getOffset();
if (event.clientX != void 0) {
this.percent = (event.clientX - this.knotWidth / 2 - this.offsetToBody) / this.lineWidth;
} else {
if (event.touches != void 0) {
this.percent = (event.touches[0].clientX - this.knotWidth / 2 - this.offsetToBody) / this.lineWidth;
} else
this.percent = (event.originalEvent.touches[0].clientX - this.knotWidth / 2 - this.offsetToBody) / this.lineWidth;
}
if (this.percent < 0)
this.percent = 0;
else if (this.percent > 1)
this.percent = 1;
//var v = this.percent * this.max;
var v = this.percent * (this.max - this.min) + this.min;
//var v = Math.round(this.percent * this.max * 10)/10; //精度为0.1
if (this.value == v)
return;
this.setValue(v);
}
SlideBar.prototype.setValueFromOutside = function (v) {
//外面的事件触发的
if (this.line.width() == 0)
return;
//不可见就不执行。
//v = Math.round(v*10)/10;
if (this.realMax != void 0) {
v = THREE.Math.clamp(v, this.min, this.realMax);
if (v > this.max)
this.changeLimit({
max: v
});
} else
v = THREE.Math.clamp(v, this.min, this.max);
this.setValue(v);
}
//-----------------------------------------------------
var transformControls;
var initTransformCtl = function (THREE) {
TransformControls.init(THREE)
TransformControls.prototype.transCtlChangeMode = function (mode) {
//if(!this.editing)return;
if (mode && this.mode != mode) {
this.mode = mode;
transformControls.children[0].showZ = this.mode != 'scale' || transformControls.scaleShowZ
}
}
,
transformControls = new TransformControls(player.camera, player.domElement, {
player: player,
dontHideWhenFaceCamera: true,
/* scaleAxis: ["x", "y"],
//隐藏了z轴。虽然参数没用上
NoScaleZ: true //整体缩放时只缩放xy轴。 */
});
transformControls.space = 'local'//为了在当前方向上平移
transformControls.setSize(1.5)
player.model.add(transformControls)
/* $(".MenuOptions[name='transform'] li").on("click", (e)=>{
transformControls.transCtlChangeMode($(e.target).attr("index"))
}) */
transformControls.transformMenuOptions = new MenuOptions({
dom: $(".MenuOptions[name='transform'] "),
uiCallBack: (o) => {
var mode = o.name == void 0 ? o.$li.attr('index') : o.name
transformControls.transCtlChangeMode(mode)
var hotpointDetail = editTool.hotpoint.hotpointDetail
hotpointDetail.find(" li[name=setPos] button[name=setSpace] ").css('display', mode == 'scale' ? 'none' : 'block')
hotpointDetail.find(" li[name=setPos] button[name=useSuitableRatio] ").css('display', mode == 'scale' ? 'block' : 'none')
hotpointDetail.find(" li[name=setPos] button[name=resetRot] ").css('display', mode == 'rotate' ? 'block' : 'none')
},
callbackWhenChose: (o) => {
}
})
transformControls.enableScaleZ = () => {
if (transformControls.mode == 'scale') {
transformControls.children[0].showZ = true
}
transformControls.scaleShowZ = true
}
transformControls.unableScaleZ = () => {
if (transformControls.mode == 'scale') {
transformControls.children[0].showZ = false
}
transformControls.scaleShowZ = false
}
}
//----------------漫游可见性---------------------------------
var VisiSet = {
setPanoVisible: false,
setTagVisible: false,
setPanoLog: false,
panoVLines: {},
//线条
panoVTemp: {},
//修改后还没保存的临时数据
tagVsetting: null,
//正在设置的热点中心点
tagsVLines: {},
//线条
//tagVTemp //修改后还没保存的临时数据
$confirmSnap: $("#camera-start"),
changeBtn: $(".toolMid .midBottom #midBtns>button").eq(1),
colors: {
green: "#00c8ae"
},
init: function () {
this.footIconSizeRatio = Math.max(player.model.size.x, player.model.size.z) / 25;
this.meshGroup = new THREE.Object3D;
this.meshGroup.name = "setVisible-group"
player.model.add(this.meshGroup)
$("#hotVisible button").on("click", () => {
VisiSet.enterSet(VisiSet.beginSetTagVisible.bind(VisiSet))
})
player.on("mode.changing", (from, to) => {
if (to == "panorama" && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog)) {
VisiSet.finishSetPanoVisible()
VisiSet.finishSetTagVisible()
VisiSet.finishSetPanoLog()
}
})
player.model.on("floor.changed", (toFloor) => {
if (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog) {
VisiSet.changePanoVisi(true, toFloor)
}
})
player.on("view.changed", (e) => {
if (e.cameraChanged && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog)) {
VisiSet.updateFootIconSize();
}
})
this.changeBtn.on("click", () => {//隐藏与显示该点
if (this.changeBtn.attr("function") == "hide") {
for (let i in this.panoVLines) {
this.panoVLines[i].visible && this.dealPanoVisible(i);
}
} else {
//显示该点时,显示周围一定距离内、到该点没有遮挡的pano
//?????
var list = player.model.panos.sortByScore([e => e.isAligned()], [(pano) => { return -pano.position.distanceTo(this.panoVsetting.position) }])
if (list.length == 1) {
console.log('仅有一个漫游点')
return;
}
var ifBlock = function (panoA, panoB) {
var A = panoA.position.clone();
var B = panoB.position.clone();
return convertTool.ifIntersectChunks(A, B, {})
}
var okList
var s = Math.max(-list[1].score * 2, 4); //i==1的一定显示
for (var i = 1; i < list.length; i++) {
if (-list[i].score < s) {
if (ifBlock(this.panoVsetting, list[i].item)) {
list[i].block = true //有阻挡
}
list[i].good = true
} else {
okList || (okList = list.filter(e => e.good && !e.block));//绝对可以使用的
if (okList.length < 2) {
if (!ifBlock(this.panoVsetting, list[i].item)) {
if (okList.length == 0) {
okList.push(list[i])
} else {//1
var lastPos = okList[0].item.position.clone().sub(this.panoVsetting.position).setY(0);
var thisPos = list[i].item.position.clone().sub(this.panoVsetting.position).setY(0);
if (lastPos.angleTo(thisPos) > Math.PI / 2) {
console.log('再加一个 角度' + THREE.Math.radToDeg(lastPos.angleTo(thisPos)))
break;
}
}
}
} else {
break;
}
}
}
if (okList.length == 0) {//如果length为0,至少加一个pano, 虽然是遮挡的
okList.push(list[0].item)
}
okList.forEach(e => this.dealPanoVisible(e.item.id))
console.log(okList)
}
})
},
enterSet: function (fun) {
var enter = function () {
if (player.modeTran.split('-')[1] != "floorplan") {
setTimeout(fun, 300)
//提前一点出现
}
player.flyToMode("floorplan", fun);
}
permitTranMode(['dollhouse', 'floorplan'])
if (player.modeTran == void 0) {
player.afterCModeFuc = () => {
enter()
}
} else
enter()
},
beginSetPanoLog: function () {
player.flying || $(".toolLeft").removeClass("unable")
if (this.setPanoLog)
return;
this.setPanoLog = true
this.panosSelect = []
this.updateFootIconSize()
this.showFootIcons(null, true);
for (let i in player.model.hots) {
player.model.hots[i].visi_ = player.model.hots[i].mesh.visible;
player.model.hots[i].mesh.visible = false
}
this.changePanoVisi(true)
},
changePanoVisi: function (state, toFloor) {
var floor = player.model.allFloorsVisible ? 'all' : (toFloor || player.model.currentFloor)
if (this.setPanoVisible) {
if (floor != 'all' && this.panoVsetting && floor != this.panoVsetting.floor) {//如果切换到其他楼,取消选中该pano
this.pauseSetPanoVisible('unsaved')
}
}
player.model.panos.forEach(e => {
if (!e.footIcon) return
if (state && !e.footIcon.visible && (floor == 'all' || floor == e.floor)) {
e.footIcon.visible = true
if (this.setPanoLog) e.addTextSprite(e.id, $('#panoIdColorTex').val(), e.footIcon)
} else if (!state || floor != 'all' && floor != e.floor) {
e.footIcon.visible = false
if (this.setPanoLog) e.removeTextSprite()
}
})
},
finishSetPanoLog: function () {
//结束 退出这个设置
if (!this.setPanoLog)
return;
//否则会加多个侦听
this.changePanoVisi(false)
this.setPanoLog = false;
//this.hideFootIcons();
this.recoverAllState2();
this.panosSelect = null
player.flyoutType = null
permitTranMode(true)
for (let i in player.model.hots) {
player.model.hots[i].mesh.visible = player.model.hots[i].visi_
}
$("#panosIdShow").val('')
},
dealPanoLogClick: function (object) {
var id = object.name == '' ? object.parent.name : object.name
var panos = player.model.panos;
var index = this.panosSelect.indexOf(id)
if (index == -1) {
this.changeFIconState(panos.index[id].footIcon, "linked")
this.panosSelect.push(id)
} else {
this.changeFIconState(panos.index[id].footIcon, false)
this.panosSelect.splice(index, 1)
}
$("#panosIdShow").val('"' + this.panosSelect.join('","') + '"');
}
,
changePanoIdColor: function (color) {
player.model.panos.forEach(e => {
e.removeTextSprite();
e.addTextSprite(e.id, color, e.footIcon)
})
}
,
//--------------
beginSetPanoVisible: function () {
player.flying || $(".toolLeft").removeClass("unable")
if (this.setPanoVisible)
return;
this.setPanoVisible = true;
this.panoVTemp = {};
this.SetOnePanoVisible(player.currentPano)
//先设置currentPano
this.$confirmSnap.text('保存当前设置').removeClass("hide")
//objects.tagManager.hideAllTags();
this.setDisplay(true)
this.updateFootIconSize()
//更新一下大小,尤其是上次换了中心点然后退出又进入但是镜头没有变化的话
for (let i in player.model.hots) {
player.model.hots[i].visi_ = player.model.hots[i].mesh.visible;
player.model.hots[i].mesh.visible = false
}
},
SetOnePanoVisible: function (pano) {
//点击某个pano后就对该pano点进行设置
if (this.panoVsetting == pano)
return;
//if (this.panoVsetting) saveLastPanoVi(this.panoVsetting);
this.panoVsetting = pano;
//记录正在修改的
this.delVisibleLines();
//删除线
this.showFootIcons(pano, true);
this.createPanoVisiLines(pano);
//创线
this.changeBtn.removeClass('hide')
},
saveLastPanoVi: function (o = {}) {
//保存刚设置过的pano
var change = [];
/* if(o.type == 'autoCompute'){
}else{ */
for (var r in this.panoVLines) {
var line = this.panoVLines[r];
if (line.name.indexOf("new") > -1 && line.visible) {
//新设置为visible且没有取消
change.push({
type: "add",
id: r
})
} else if (line.name.indexOf("new") == -1 && !line.visible) {
//旧的且已经取消
change.push({
type: "sub",
id: r
})
}
}
/* } */
if (change.length) {
//添加双向的neighbour:
var self = this.searchNeib(this.panoVsetting.id)
//var seeMarkers_self = self.seeMarkers;
var neighbourUUIDs_self = self.neighbourUUIDs
var neighbourPanos_self = self.neighbourPanos;
for (var i = 0; i < change.length; i++) {
var other = this.searchNeib(change[i].id)
//var seeMarkers = other.seeMarkers;
var neighbourUUIDs = other.neighbourUUIDs;
var neighbourPanos = other.neighbourPanos;
if (change[i].type == "add") {
//seeMarkers.push(this.panoVsetting.id);
neighbourUUIDs.push(this.panoVsetting.id);
neighbourPanos[this.panoVsetting.id] = true;
//seeMarkers_self.push(change[i].id);
neighbourUUIDs_self.push(change[i].id);
neighbourPanos_self[change[i].id] = true;
} else {
//var index = seeMarkers.indexOf(this.panoVsetting.id);
//index > -1 && seeMarkers.splice(index, 1);
var index = neighbourUUIDs.indexOf(this.panoVsetting.id);
index > -1 && neighbourUUIDs.splice(index, 1);
neighbourPanos[this.panoVsetting.id] = false;
//var index = seeMarkers_self.indexOf(change[i].id);
//index > -1 && seeMarkers_self.splice(index, 1);
var index = neighbourUUIDs_self.indexOf(change[i].id);
index > -1 && neighbourUUIDs_self.splice(index, 1);
neighbourPanos_self[change[i].id] = false;
}
this.panoVTemp[change[i].id] = {
//后面两个是作为保存到后台的数据存储,临时需要用到的是第一个
neighbourPanos: neighbourPanos,
//seeMarkers: seeMarkers,
neighbourUUIDs: neighbourUUIDs
}
}
this.panoVTemp[this.panoVsetting.id] = {
//加上自己
neighbourPanos: neighbourPanos_self,
//seeMarkers: seeMarkers_self,
neighbourUUIDs: neighbourUUIDs_self
}
}
},
pauseSetPanoVisible: function (type) {
//暂停 因为点击了保存设置 但没有退出设置
if (!this.setPanoVisible)
return;
if (type == "unsaved") {
//中途点击pano从而停止一个热点的设置
this.saveLastPanoVi();
} else {
this.panoVTemp = {};
//清空数据
}
this.delVisibleLines();
this.showFootIcons();
//清空选择
var lastPanoSetting = this.panoVsetting;
this.panoVsetting = null;
lastPanoSetting && this.changeFIconState2(lastPanoSetting.footIcon, this.checkHasNeighbor(lastPanoSetting))
//这句要放在this.panoVsetting = null后。 根据可见性更改透明度
this.changeBtn.addClass('hide')
},
//按理说改变了neighbourPano,tag的初始visible也要改。但是这样还要考虑已经改过的tag。。很麻烦
finishSetPanoVisible: function () {
//结束 退出这个设置
if (!this.setPanoVisible)
return;
//否则会加多个侦听
this.setPanoVisible = false;
//this.hideFootIcons();
this.delVisibleLines();
//objects.tagManager.showAllTags();
this.recoverAllState2();
this.panoVsetting = null;
this.panoVTemp = {};
player.flyoutType = null
this.$confirmSnap.addClass("hide")
permitTranMode(true)
this.setDisplay(false)
for (let i in player.model.hots) {
player.model.hots[i].mesh.visible = player.model.hots[i].visi_
}
},
changeVisiBtnState: function (state) {
this.changeBtn.attr("function", state ? "hide" : "show")
this.changeBtn.html(state ? "隐藏该点位置" : "显示该点位置")
},
recoverAllState2: function () {
//为了热点可视恢复成pano全部可见
if (!this.footIcons) return;
for (var i = 0; i < this.footIcons.length; i++) {
this.footIcons[i].material.uniforms.opacity.value = 1;
this.footIcons[i].material.uniforms.map.value = footTex1;
}
},
afterSavePanoVisibles: function () {
//实施:
var panos = player.model.panos;
for (var i in this.panoVTemp) {
var pano = panos.index[i];
//pano.seeMarkers = this.panoVTemp[i].seeMarkers;
pano.neighbourUUIDs = this.panoVTemp[i].neighbourUUIDs;
pano.neighbourPanos = this.panoVTemp[i].neighbourPanos;
}
if (!this.checkHasNeighbor(player.currentPano)) {
//currentPano变为孤立点 就要换一个防止飞入
var list = panos.sortByScore([pano => {
return this.checkHasNeighbor(pano)
}
], [function (pano) {
return -pano.position.distanceTo(player.currentPano.position)
}
])
if (list && list.length) {
player.currentPano = list[0].pano;
//找最近的一非孤立点
//this.noPanoHasNeighbor = false; //更新状态
} else {//this.noPanoHasNeighbor = true; //更新状态
}
} else {//this.noPanoHasNeighbor = false; //更新状态
}
//dataDeal.done();
//暂时:
this.pauseSetPanoVisible()
this.updateFootIconSize()
//更新一下center大小 写在最后
},
//最佳推荐操作顺序: 先设置pano可见性 再创建热点 这样热点的visible正确些,否则之后再设置热点可见性会改更多
savePanoVisibles: function () {
//保存
if (this.panoVsetting)
this.saveLastPanoVi(this.panoVsetting);
//获取最后设置的那个热点的改动
var PanoData = [];
for (var i in this.panoVTemp) {
PanoData.push({
//希望算法部不会更改index排序,或者更改后能将visible信息一并更改
panoID: i,
//visibles: this.turnToPanoIndex(this.panoVTemp[i].seeMarkers),
visibles3: this.turnToPanoIndex(this.panoVTemp[i].neighbourUUIDs)
})
}
if (PanoData.length == 0) {
//没改变
alert("保存成功")
return;
}
/* this.afterSavePanoVisibles()
alert("保存成功")
console.log(JSON.stringify(PanoData)) */
$.ajax({
method: 'POST',
url: '/api/cms/scene/roamViable',
headers: {
'Content-Type': 'application/json',
token: token
},
contentType: 'application/json',
data: JSON.stringify({
data: JSON.stringify(PanoData),
sceneCode: window.number
}),
success: (data) => {
if (data.code === 0) {
this.afterSavePanoVisibles()
alert("保存漫游可行成功")
} else
alert("保存漫游可行失败")
if (data.code === 5001) {
alert('请重新登录')
window.location.href='/backstage/#/login'
localStorage.removeItem(TOKEN_KEY)
location.reload()
}
}
,
fail: function () {
alert("保存漫游可行失败")
}
})
},
searchNeib: function (panoId) {
//寻找某pano的相关neighbour 可能是修改过的
var panos = player.model.panos;
var o = {};
if (this.panoVTemp[panoId]) {
//o.seeMarkers = this.panoVTemp[panoId].seeMarkers;
o.neighbourUUIDs = this.panoVTemp[panoId].neighbourUUIDs;
o.neighbourPanos = this.panoVTemp[panoId].neighbourPanos;
} else {
//o.seeMarkers = panos.index[panoId].seeMarkers.slice(0);
o.neighbourUUIDs = panos.index[panoId].neighbourUUIDs.slice(0);
o.neighbourPanos = CloneObject(panos.index[panoId].neighbourPanos);
}
return o;
},
turnToPanoIndex: function (panoArr) {
var array = [];
for (var i = 0; i < panoArr.length; i++) {
var pano = player.model.panos.index[panoArr[i]]//可能undefined,只是存在在panoListOriData中,因在this.data.sweeps[e.uuid].enabled是false
if (pano) {
var index = window.panoListOriData.indexOf(pano.id)
array.push(index);
}
}
return array;
},
setDisplay: function (state) {
var panos = player.model.panos;
if (state) {
this.$confirmSnap.text('保存当前设置');
this.$confirmSnap.removeClass('hide');
} else {
this.$confirmSnap.addClass('hide');
this.changeBtn.addClass('hide')
}
player.path.currentPanoMarker.mesh.visible = !state;
player.reticule.visible = !state;
this.changePanoVisi(state)
},
delVisibleLines: function () {
//xzw add 所有线都删除
for (var i in this.tagsVLines) {
this.tagsVLines[i].geometry.dispose();
this.tagsVLines[i].material.dispose();
this.meshGroup.remove(this.tagsVLines[i]);
delete this.tagsVLines[i];
}
for (var i in this.panoVLines) {
this.panoVLines[i].geometry.dispose();
this.panoVLines[i].material.dispose();
this.meshGroup.remove(this.panoVLines[i]);
delete this.panoVLines[i];
}
},
//--------panoVisible
createPanoVisiLines: function (pano) {
// pano可见性线条
var neighbours = this.panoVTemp[pano.id] && this.panoVTemp[pano.id].neighbourPanos || pano.neighbourPanos;
for (var r in neighbours) {
if (neighbours[r] && r != pano.id) {
this.createPanoSingleLine(pano, "old", r)
}
}
},
createPanoSingleLine: function (pano, type, id) {
//pano是中心
var panos = player.model.panos;
var p2 = panos.index[id].footIcon.position.clone()
/* .sub(player.model.position) */
var line = LineDraw.createLine([pano.footIcon.position.clone()/* .sub(this.position) */
, p2], {
color: this.colors.green
});
this.meshGroup.add(line);
line.name = "PanoVL-" + type + "-" + id;
this.panoVLines[id] = line;
this.changeFIconState(panos.index[id].footIcon, "linked")
},
dealPanoVisible: function (id) {
//外部调用
var panos = player.model.panos;
if (this.panoVsetting) {
if (id == this.panoVsetting.id) {
//关闭当前pano设置
this.pauseSetPanoVisible('unsaved')
} else {
var link;
//结果是否连接
if (this.panoVLines[id]) {
this.panoVLines[id].visible = !this.panoVLines[id].visible;
link = this.panoVLines[id].visible;
this.changeFIconState(panos.index[id].footIcon, this.panoVLines[id].visible ? "linked" : false)
} else {
this.createPanoSingleLine(this.panoVsetting, "new", id)
link = true;
}
if (link) {
//如果连接上了,直接判断该点是可见的(有附近点),(不能通过checkHasNeighbor来判断,因为新增的线条可能不在它的neighbour中
this.changeFIconState2(panos.index[id].footIcon, true)
this.changeFIconState2(panos.index[this.panoVsetting.id].footIcon, true)
} else {
//否则需要checkHasNeighbor
this.changeFIconState2(panos.index[id].footIcon, this.checkHasNeighbor(panos.index[id]))
this.changeFIconState2(panos.index[this.panoVsetting.id].footIcon, this.checkHasNeighbor(this.panoVsetting))
}
/* if(window.routeArray){//箭头路线
if(this.panoVLines[id].visible)window.routeArray.push(id)
else{
let index = window.routeArray.indexOf(id)
index > -1 && routeArray.splice(index, 1)
}
} */
}
} else {
//点击开始设置要设置的pano
this.SetOnePanoVisible(panos.index[id])
}
this.updateFootIconSize()
},
showFootIcons: function (pano, isPanovisible) {
if (!this.footIcons) {
footTex1 = Texture.load("images/edit/End_128.png");
footTex2 = Texture.load("images/edit/End_unable_128.png");
footTex1.anisotropy = footTex2.anisotropy = 4
this.footIcons = [];
var scale = 0.4;
scale *= 40 / Math.sqrt(Math.min($("#player").width(), $("#player").height()));
//屏幕越小,放得越大
scale = THREE.Math.clamp(scale, 0.3, 0.7)
//console.log("scale"+scale)
var geo = new THREE.PlaneGeometry(scale, scale, 1, 1)
var panos = player.model.panos;
for (var r in panos.index) {
if (!panos.index[r].isAligned())
continue;
var t = THREE.UniformsUtils.clone(shaders.waypoint.uniforms);
t.map.value = footTex1
t.color.value.set("#ffffff");
var mat = new THREE.RawShaderMaterial({
vertexShader: shaders.waypoint.vertexShader,
fragmentShader: shaders.waypoint.fragmentShader,
uniforms: t,
side: THREE.DoubleSide,
transparent: !0,
depthWrite: !1,
depthTest: false,
name: "footIcon"
})
var foot = new THREE.Mesh(geo, mat)
foot.position.copy(panos.index[r].floorPosition.clone()) /* panos.index[r].floorPosition.clone() *///不用floorPosition是因为有出现和position的水平位置不一样的点,一般是偏移很远的不可见点,拍摄的bug
foot.lookAt(foot.position.clone().add(new THREE.Vector3(0, 1, 0)));
foot.name = panos.index[r].id;
foot.visible = false;
foot.renderOrder = 6,
panos.index[r].footIcon = foot;
this.meshGroup.add(foot);
this.footIcons.push(foot)
}
}
for (var i = 0; i < this.footIcons.length; i++) {
this.changeFIconState(this.footIcons[i], false)
var panos = player.model.panos;
if (isPanovisible) {
this.changeFIconState2(this.footIcons[i], this.checkHasNeighbor(panos.index[this.footIcons[i].name], "showFoot"))
}
if (pano && (this.footIcons[i].name == pano.id)) {
//pano为中心 或者 currentPano 所以放大一点
this.footIcons[i].oriScale = new THREE.Vector3(1.5, 1.5, 1.5)
if (isPanovisible) {
//currentPano特殊些:
this.changeFIconState(this.footIcons[i], "center")
//this.footIcons[i].Unclick = true;//不让点击和hover
}
} else {
this.footIcons[i].oriScale = new THREE.Vector3(1, 1, 1)
}
}
},
checkHasNeighbor: function (pano, state) {
//检查当前状态pano点是否有可通行点
var neighbours = /* this.panoVTemp && */
this.panoVTemp[pano.id] ? this.panoVTemp[pano.id].neighbourPanos : pano.neighbourPanos;
if (state != "showFoot" && pano == this.panoVsetting) {
//是中心点的话。state == "showFoot"代表是showFootIcon时, 这时候线还没创建,无法用线判断中心点有几个相邻点,直接用neighbourPanos
for (var i in this.panoVLines) {
if (this.panoVLines[i].visible) {
return true;
//有一条线即可
}
}
return;
}
for (var i in neighbours) {
if (i == pano.id)
continue;
if (neighbours[i]) {
if (this.panoVsetting && this.panoVsetting.id == i && this.panoVLines[pano.id] && !this.panoVLines[pano.id].visible)
continue;
return true;
}
}
return false;
},
/* ifAllPanoNoNeighbor : function(){//检查是否全是孤立点
var panos = player.model.panos;
for(var i in panos.index){
if(this.checkHasNeighbor(panos.index[i])){
return false;
}
}
this.noPanoHasNeighbor = true;
return true;//是全部没有neighbour
}, */
changeFIconState: function (footIcon, state) {
var color = state == "linked" ? this.colors.green : (state == "center" ? /* "#d7f244" */
"#d5f12e" : "#ffffff");
footIcon.material.uniforms.color.value.set(color)
},
changeFIconState2: function (footIcon, state) {
//是可见点还是不可见点
if (state) {
footIcon.material.uniforms.map.value = footTex1;
if (this.panoVsetting) {
if (this.panoVsetting.id != footIcon.name) {
footIcon.material.uniforms.opacity.value = 1;
} else {
this.changeVisiBtnState(true)
}
}
} else {
//不可见
footIcon.material.uniforms.map.value = footTex2;
if (!this.panoVsetting || this.panoVsetting.id != footIcon.name) {
//非中心点时
footIcon.material.uniforms.opacity.value = 0.5;
} else {
//变为中心点时
footIcon.material.uniforms.opacity.value = 1;
this.changeVisiBtnState(false)
}
}
},
hideFootIcons: function () {
if (!this.footIcons)
return;
for (var i = 0; i < this.footIcons.length; i++) {
this.footIcons[i].visible = false;
}
},
updateFootIconSize: function () {
//根据相机位置 改变footIcon大小,使在范围内看到的热点大小一致,防止太小点击不到
if (!this.footIcons) return;
if (player.mode == 'floorplan') {
var s = player.cameraControls.controls.floorplan.absoluteScale * 2.8
s = THREE.Math.clamp(s, 0.5 * this.footIconSizeRatio, 1.4 * this.footIconSizeRatio);
this.footIcons.forEach(function (f) {
try {
f.scale.copy(f.oriScale).multiplyScalar(s);
} catch (e) {
console.log(e)
}
})
} else {
let maxDis = 7, maxScale = 2 * this.footIconSizeRatio, k = maxScale / maxDis
this.footIcons.forEach(function (f) {
let s
let dis = f.position.distanceTo(player.position)
if (dis >= maxDis) s = maxScale
else s = dis * k
f.scale.copy(f.oriScale).multiplyScalar(s);
//f.quaternion.copy(player.camera.quaternion)
})
}
},
resetPanosVisiByModel: function () {//一键计算所有漫游可行 (计算后自动连接,但不保存) 多楼层还没试过
$('.waiting').addClass('showloading');
$('.pinBottom .allFloorBtn').click()//全部楼层显示
let begin = () => {
this.pauseSetPanoVisible("unsaved")
var ifBlock = function (panoA, panoB) {
var A = panoA.position.clone();
var B = panoB.position.clone();
return !!convertTool.ifIntersectChunks(A, B, {})
}
player.model.panos.list.forEach(pano1 => {
this.SetOnePanoVisible(pano1)//开始设置pano1
player.model.panos.list.forEach(pano2 => {
if (pano1 == pano2) return
var visiNew = !ifBlock(pano1, pano2)
var visiOld = !!(this.panoVLines[pano2.id] && this.panoVLines[pano2.id].visible)
if (visiNew != visiOld) {
//console.log('修改 '+pano1.id+'-'+pano2.id)
this.dealPanoVisible(pano2.id)//修改
}
})
this.pauseSetPanoVisible('unsaved')//修改pano1结束
})
$('.waiting').removeClass('showloading');
manage.showInfo("修改成功,可以点击漫游点查看。点击保存当前设置后生效。")
}
setTimeout(() => {
if (this.setPanoVisible) {
begin()
}
}, 100)
},
//========热点可见性==============
beginSetTagVisible: function () {
if (this.setTagVisible)
return;
$(".toolTop").addClass("unable")
$("#hotVisible button").addClass("unable")
$("#hotVisible label").removeClass('hide')
this.setTagVisible = true;
this.tagVTemp = {};
this.$confirmSnap.text('完成设置').removeClass("hide")
//objects.tagManager.hideAllTags();
for (let i in player.model.hots) {
player.model.hots[i]._isSprite = player.model.hots[i].info.isSprite;
player.model.hots[i].info.isSprite = true;
player.model.hots[i].material_.depthTest = false;
player.model.hots[i].position.copy(player.model.hots[i].info.position);//覆盖transformAtPanos
player.model.hots[i].update(player)
}
this.setDisplay(true)
this.updateFootIconSize()
//更新一下大小,尤其是上次换了中心点然后退出又进入但是镜头没有变化的话
},
SetOneTagVisible: function (tag) {
//点击某个热点后就对该热点进行设置,或者在热点修改时对其进行设置
if (this.tagVsetting == tag)
return;
if (this.tagVsetting) {
this.saveLastTagVi(this.tagVsetting);
//this.tagVsetting.setElemType(this.tagVsetting.style, this.tagVsetting.styleImageURL);
}
this.tagVsetting = tag;
//记录正在修改的
this.delVisibleLines();
//删除线
this.showFootIcons(player.currentPano);
this.changePanoVisi(true)
this.createTagVisiLines(tag);
//创线
this.updateFootIconSize()
//更新一下大小,尤其是上次换了中心点然后退出又进入但是镜头没有变化的话
},
saveLastTagVi: function () {
//保存刚设置过的tag
var change = false;
var newVPs = this.tagVTemp[this.tagVsetting.sid] || this.tagVsetting.info.visiblePanos.slice(0);
for (var r in this.tagsVLines) {
var line = this.tagsVLines[r];
if (line.name.indexOf("new") > -1 && line.visible) {
//新设置为visible且没有取消
newVPs.push(r)
change = true;
//console.log("add: "+r)
} else if (line.name.indexOf("new") == -1 && !line.visible) {
//旧的且已经取消
var i = newVPs.indexOf(r);
if (i == -1) {
console.log("visiblePanos删除error");
continue;
}
newVPs.splice(i, 1);
change = true;
//console.log("sub: "+r)
}
}
if (change) {
this.tagVTemp[this.tagVsetting.sid] = newVPs;
}
},
pauseSetTagVisible: function () {
//pc保存后删除连线 但还在继续设置 点选热点即开始
if (!this.setTagVisible || !this.tagVsetting)
return;
//this.tagVsetting.setElemType(this.tagVsetting.style, this.tagVsetting.styleImageURL );
this.delVisibleLines();
//this.hideFootIcons();
this.changePanoVisi(false)
this.tagVTemp = {};
this.tagVsetting = null;
},
finishSetTagVisible: function () {
if (!this.setTagVisible)
return;
$(".toolTop").removeClass("unable")
$("#hotVisible button").removeClass("unable")
$("#hotVisible label").addClass('hide')
this.pauseSetTagVisible();
this.setTagVisible = false;
this.setDisplay(false)
this.$confirmSnap.addClass("hide")
permitTranMode(true)
/* for (var r in objects.tagManager.tags) {
if(objects.tagManager.tags[r].state == "videoPanoFlag")continue;
objects.tagManager.tags[r].disc.visible = false;
objects.tagManager.tags[r].disc.material.depthTest = true;
} */
for (let i in player.model.hots) {
player.model.hots[i].info.isSprite = player.model.hots[i]._isSprite;
player.model.hots[i].info.isSprite || player.model.hots[i].rotation.copy(player.model.hots[i].info.rotation)
player.model.hots[i].material_.depthTest = true;
}
},
saveTagVisibles: function () {
if (this.tagVsetting)
this.saveLastTagVi(this.tagVsetting);
for (var i in this.tagVTemp) {
//保持成功于是生效
player.model.hots[i].setVisiblePanos(this.tagVTemp[i])
}
this.finishSetTagVisible()
//还是保存完直接结束吧,因为现在热点可视不放在单独的设置页面了
},
createTagVisiLines: function (tag) {
// 热点可见性线条
var panos = player.model.panos;
var visibleList = this.tagVTemp[tag.sid] || tag.info.visiblePanos;
//如果是刚在设置的要读取设置过的数据
for (var r = 0; r < visibleList.length; r++) {
var pano = panos.index[visibleList[r]];
this.createTagSingleLine(pano, "old", tag)
}
},
createTagSingleLine: function (pano, type, tag) {
var panos = player.model.panos;
var line = LineDraw.createLine([pano.footIcon.position.clone()/* .sub(this.position) */
, tag.info.position.clone()], {
color: this.colors.green
});
this.meshGroup.add(line);
line.name = "tagVL-" + type + "-" + pano.id;
this.tagsVLines[pano.id] = line;
this.changeFIconState(panos.index[pano.id].footIcon, "linked")
},
dealTagVisible: function (tag, panoName) {
//外部调用
var panos = player.model.panos;
if (this.tagsVLines[panoName]) {
this.tagsVLines[panoName].visible = !this.tagsVLines[panoName].visible;
this.changeFIconState(panos.index[panoName].footIcon, this.tagsVLines[panoName].visible ? "linked" : false)
} else {
this.createTagSingleLine(panos.index[panoName], "new", tag)
}
},
delVisibleLines: function () {
//xzw add 所有线都删除
for (var i in this.tagsVLines) {
this.tagsVLines[i].geometry.dispose();
this.tagsVLines[i].material.dispose();
this.meshGroup.remove(this.tagsVLines[i]);
delete this.tagsVLines[i];
}
for (var i in this.panoVLines) {
this.panoVLines[i].geometry.dispose();
this.panoVLines[i].material.dispose();
this.meshGroup.remove(this.panoVLines[i]);
delete this.panoVLines[i];
}
},
//------------
/* resetTagVisiByModel : function(){//自动计算所有热点的可视 当模型修改后所有的热点可视都会重新自动计算(用户的设置将被覆盖)
var visiTags = [];
for(var i in objects.tagManager.tags){
var tag = objects.tagManager.tags[i];
if(tag.state == "videoPanoFlag")continue;
var visiblePanos = tag.getVisiblePanos();
visiTags.push({sid:tag.sid, value:visiblePanos})
}
return visiTags;
},
afterResetTagVisibles : function(visiTags){
visiTags.forEach((info)=>{
objects.tagManager.tags[info.sid].setVisiblePanos(info.value);
})
if(objects.player.mode == "panorama")objects.tagManager.updateVisible("panorama");
},
resetVisiblesByModel : function(){//自动计算所有热点和漫游点的可视
this.resetTagVisiByModel()
} */
}
function permitTranMode(state) {
if (state instanceof Array) {//仅显示state包含的模式
$(".pinBottom.left").removeClass('hide')
$(".pinBottom.left .viewContainer>*:not(#gui-modes-map)").addClass('hide');
$(".pinBottom.left #gui-modes-map>*").addClass('hide');
//注:panorama需转为inside
state.forEach(m => $(".pinBottom.left #gui-modes-" + m).removeClass('hide'))
player.roomLebelClickUnabled = true
} else {
if (state) {
player.roomLebelClickUnabled = false
$(".pinBottom.left").removeClass('hide'),
$(".pinBottom.left .viewContainer>*").removeClass('hide'),
$(".pinBottom.left #gui-modes-map>*").removeClass('hide')
} else {
player.roomLebelClickUnabled = true
$(".pinBottom.left").addClass('hide');
}
}
//一旦存在有隐藏的模式,必定会隐藏导览等其他按钮。
}
function randomWord(randomFlag, min, max) {
//随机字符串
var str = ""
, range = min
, arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
if (randomFlag) {
// 随机长度
range = Math.round(Math.random() * (max - min)) + min;
}
for (var i = 0; i < range; i++) {
var pos = Math.round(Math.random() * (arr.length - 1));
str += arr[pos];
}
return str;
}
function getRandomSid() {
//5-7位随机字符串 + 6位时间 为热点准备
var pre = randomWord(true, 5, 7);
var post = new Date().getTime() + "";
var len = post.length;
post = post.substring(len - 8, len - 5) + post.substring(len - 3, len)
//其实还是有可能重复的....
return pre + post;
}
function searchParent(searchArea, o, maxTimes) {
//是否是某种元素的下级,并找出该元素
maxTimes = maxTimes || 20;
var count = 0
var f = function (dom) {
if (o.id && o.id == dom.id)
return dom
else if (o.className && dom.classList && dom.classList.contains(o.className))
return dom
else if (o.tagName && dom.tagName && o.tagName.toUpperCase() == dom.tagName.toUpperCase())
return dom
}
var find;
while (searchArea && count < maxTimes) {
if (find = f(searchArea))
return find
searchArea = searchArea.parentNode;
count++;
}
}
function musicPlayBoxBind($dom, addCallback, delCallback) {
var musicBox = {
hasMusic: false,
show: function (/* mediaDom, */name, url) {
/* mediaDom = mediaDom || $dom
mediaDom.find(".innerBtn").text("替换");
mediaDom.find(".playBox").removeClass("hide");
mediaDom.find(".title").text(name);
mediaDom.find('a').attr('href', url);
musicBox.hasMusic = true */
$dom.find(".innerBtn").text("替换");
$dom.find(".playBox").removeClass("hide");
$dom.find(".title").text(name);
$dom.find('a').attr('href', url);
musicBox.hasMusic = true
},
addMusic: function (e) {
if (!e.target.files.length) return;
var file = e.target.files[0];
if (!/audio\/\w+/.test(file.type)) {
alert("文件必须为音乐!");
return false;
}
//限制大小不大于8m
if (!restrictedSize(file, _musicMaxWeight)) {
return false
}
//var mediaDom = $(searchParent(e.target, { className: 'mediaUpload' }));
musicBox.show(/* mediaDom, */file.name, URL.createObjectURL(file))
addCallback && addCallback(file)
},
delMusic: function () {//手动点击删除
musicBox.hide()
delCallback && delCallback()
},
hide: function (e) {//清空并隐藏
//var mediaDom = e ? $(searchParent(e.target, { className: 'mediaUpload' })) : $dom
$dom.find('a').attr('href', "");
$dom.find(".playBox").addClass("hide");
$dom.find(".innerBtn").text("上传");
$dom.find("input").val("")//.removeAttr("data-hotbgm");
musicBox.hasMusic = false
},
getSrc: function () {
return this.hasMusic && $dom.find('a').attr('href');
},
getName: function () {
return this.hasMusic && $dom.find(".title").text();
},
getFile: function () {//获取刚上传的文件
return this.hasMusic && $dom.find("input")[0].files[0]
}
}
$dom.find("input").on("change", musicBox.addMusic)
/* $dom.find("input").on("click", function() {
mediaUpload
}); */
//删除音乐
$dom.on("click", ".delete", musicBox.delMusic)
return musicBox;
}
class ListBox {//下拉列表
//elemArr:初始的列表,内含每项的dom.
constructor(elemArr, $rootDom, options = {}) {
this.listDom = $rootDom.find('ul.list')
this.listTitle = $rootDom.find('.selection')
this.chosenItem = null
this.options = options;
this.bindEvents()
elemArr.forEach(($dom, i) => {
this.addItem($dom)
})
}
updateSelectDisplay(o) {
this.listDom.children().removeClass('selected')
this.chosenItem && this.chosenItem.addClass("selected")
this.options.selectFun(o)
}
selectFromOutSide(index, o) {
if (index == null) {
var defaultItem = this.listDom.find('.forbitEdit'); //若存在默认选项
if (defaultItem.length) {
index = defaultItem.index()
}
}
this.chosenIndex = index;
this.chosenItem = index == void 0 ? null : this.listDom.children().eq(index)
this.updateSelectDisplay(o)
}
addItem($dom) {
this.listDom.prepend($dom)
if (this.options.addFun) {
this.options.addFun($dom)
}
$dom.on('click', () => {
this.chosenItem = $dom;
this.chosenIndex = $dom.index();
this.updateSelectDisplay()
})
}
removeItem($dom) {
$dom.remove()
if (this.chosenItem && this.chosenItem[0] == $dom[0]) {
this.selectFromOutSide(null)
//this.chosenItem = this.chosenIndex = null
}
if (this.options.delFun) {
this.options.delFun($dom)
}
}
saveTemp() {//编辑热点时保存一份副本
this.temp = Array.from(this.listDom.children()).reverse().map((li) => {
return li.outerHTML
})
this.options.saveTemp && this.options.saveTemp(this)
}
recover() {//取消编辑时恢复
this.listDom.html('')
this.temp.forEach(html => {
this.addItem($(html));
})
this.options.recover && this.options.recover(this)
this.chosenItem = this.chosenIndex = null
//this.selectFromOutSide(this.chosenIndex)
}
bindEvents() {
this.listTitle.on('click', (e) => {
e.stopPropagation()
this.listDom.toggleClass('hide')
})
document.addEventListener('click', () => {
this.listDom.addClass('hide')
})
}
}
class ButtonBase {
constructor(o = {}) {
this.dom = o.dom
this.uiCallBack = o.uiCallBack
this.callbackWhenChose = o.callbackWhenChose //只有点击选择才会触发
}
}
class MenuOptions extends ButtonBase {
constructor(o = {}) {
super(o)
this.dom.find("li").on("click", (e) => {
var $elem = $(e.target);
this.updateChoseAtUI({ $li: $elem })
this.callbackWhenChose && this.callbackWhenChose({ $li: $elem })
})
}
updateChoseAtUI(o = {}) {
this.dom.find('li').removeClass("chosen");
if (o.$li) {
o.$li.addClass("chosen");
} else {
this.dom.find("li[index=" + o.name + "]").addClass("chosen");
}
this.uiCallBack && this.uiCallBack(o)
}
getSelectName() {
return this.dom.find('li.chosen').attr('index')
}
}
class CheckBox extends ButtonBase {
constructor(o = {}) {
super(o)
this.dom.on("change", (e) => {
var name = $(e.target).attr('name')
this.uiCallBack && this.uiCallBack(e.target.checked, name)
this.callbackWhenChose && this.callbackWhenChose(e.target.checked, name)
})
}
updateChoseAtUI(checked, name) {
var dom
if (name) dom = this.dom.filter('[name=' + name + ']')[0]
else dom = this.dom[0]
dom.checked = checked //this.dom.prop("checked")
this.uiCallBack && this.uiCallBack(checked, name)
}
checked(name) {
var dom
if (name) dom = this.dom.filter('[name=' + name + ']')[0]
else dom = this.dom[0]
return dom.checked
}
}
function setDraggable(o = {}) {
let findTarget = (event) => {
let target;
for (let name of o.dragItemClassName) {
let tar = searchParent(event.target, { className: name }, o.maxDepth || 7);
if (tar) {
target = tar; break;
}
}
return target
}
let draging = null;
let dragStart = (event) => {
event.dataTransfer.setData("te", event.target.innerText); //不能使用text,firefox会打开新tab
draging = findTarget(event);
}
let dragOver = (event) => {
event.preventDefault();
let target = findTarget(event);
// 判断dragover是否发生在LI元素上
if (target && target !== draging) {
let dragingIndex = $(draging).index()//draging.querySelector('#index');
let targetIndex = $(target).index()//target.querySelector('#index');
var targetRect = target.getBoundingClientRect();
var dragingRect = draging.getBoundingClientRect();
if (target && target.animated) {
return;
}
let ulElem = target.parentNode;
// 寻找到 ul节点
if (getIndex(draging) < getIndex(target)) {
//dragingIndex.innerText = [targetIndex.innerText, targetIndex.innerText = dragingIndex.innerText][0];
// 交换两个节点的序号
if (event.clientY < targetRect.top + targetRect.height * 0.3) return
ulElem.insertBefore(draging, target.nextSibling);
//dragingIndex.innerText = [targetIndex.innerText, targetIndex.innerText = dragingIndex.innerText][0];// 交换两个节点的序号
} else {
//dragingIndex.innerText = [targetIndex.innerText, targetIndex.innerText = dragingIndex.innerText][0];
if (event.clientY > targetRect.bottom - targetRect.height * 0.3) return
ulElem.insertBefore(draging, target);
//dragingIndex.innerText = [targetIndex.innerText, targetIndex.innerText = dragingIndex.innerText][0];
}
_animate(dragingRect, draging);
_animate(targetRect, target);
o.callback && o.callback(o.ul, target)
//var ul = searchParent(event.target, { className: 'tourList' })
//reIndexTourList(ul)
}
}
o.ul.ondragstart = dragStart
o.ul.ondragover = dragOver
}
function rebuildWidget(widget) {//改写替换部分UI成可折叠的
widget = $(widget)
widget.addClass('group-widget')
let title = widget.find('.itemTitle span')[0].innerText;
let group = $(`
`)
widget.find('.itemTitle').eq(0).remove()
let children = Array.from(widget.children())
children.forEach(child => {
group.find('.inner>div').append(child)
})
widget.append(group)
}
function setToggle(widget) {//效果展开
let header = $(widget).find('.header')
let inner = $(widget).find('.inner')
header.on("click", function (e) {
header.toggleClass('closed')
inner.toggleClass('closed')
})
}
function setWidgeOpen(widget, open) {
let header = widget.find('.header')
let inner = widget.find('.inner')
if (open) {
header.removeClass('closed')
inner.removeClass('closed')
} else {
header.addClass('closed')
inner.addClass('closed')
}
}
function closeWidgets(classes) {
classes.forEach((cla) => {
let widge = $(`#hotpointDetail .content>ul>li[name=${cla}]`)
setWidgeOpen(widge, false)
})
}
Array.from($("#hotpointDetail .content>ul>li")).forEach((group) => {
rebuildWidget(group)
setToggle(group)
})
closeWidgets(['setPos', 'model'])
/* class OnOffSwitch extends CheckBox{
constructor(o={}){
super(o)
}
}
*/
/*
待加功能:
//boxhelper改成粗线
热点可视时改成一样大小
热点可视insight优化
hover到热点时列表滚动到这一项
释放geometry内存 、texture
*/