(function (global, undefined) {
var _camera, _scene, _renderer;
var _cameraOrtho, _sceneOrtho;
var _fov = 75;
var _pRadius = 1000;
var _raycaster;
var _container;
var _isUserInteracting = false;
var _lon = 0, _lat = 0;
var _onPointerDownLon = 0, _onPointerDownLat = 0;
var _onPointerDownPointerX = 0, _onPointerDownPointerY = 0;
var _mouse = new THREE.Vector2();
var _clickableObjects = [];
var _sprites = [];
var _lables = [];
var _count1 = 1;
var options = {
container: 'panoramaConianer',//容器
url: 'resources/img/panorama/pano-7.jpg',//全景图路径
lables: [],//标记 {position:{lon:114,lat:38},logoUrl:'lableLogo.png',text:'我是一个标记'}
widthSegments: 60,//水平切段数
heightSegments: 40,//垂直切段数(值小粗糙速度快,值大精细速度慢)
pRadius: 1000,//全景球的半径,推荐使用默认值
minFocalLength: 1,//镜头最a小拉近距离
maxFocalLength: 100,//镜头最大拉近距离
sprite: 'label', // label,icon
onClick: () => { }
}
function tpanorama(opt) {
this.render(opt);
}
tpanorama.prototype = {
constructor: this,
def: {},
render: function (opt) {
this.def = extend(options, opt, true);
document.getElementById(this.def.container).innerHTML = '';
_lables = [];
initContainer(this.def.container);
initCamera();
initRaycaster();
makePanorama(this.def.pRadius, this.def.widthSegments, this.def.heightSegments, this.def.url);
initRenderer();
initLable(this.def.lables, this.def.sprite);
_container.addEventListener('mousedown', onDocumentMouseDown, false);
_container.addEventListener('mousemove', onDocumentMouseMove, false);
_container.addEventListener('mouseup', onDocumentMouseUp, false);
_container.addEventListener('mousewheel', (e) => {
onDocumentMouseWheel(e, this.def.minFocalLength, this.def.maxFocalLength);
}, false);
_container.addEventListener('DOMMouseScroll', (e) => {
onDocumentMouseWheel(e, this.def.minFocalLength, this.def.maxFocalLength);
}, false);
_container.addEventListener('click', onDocumentMouseClick.bind(this), false);
global.addEventListener('resize', onWindowResize, false);
animate();
}
}
function extend(o, n, override) {
for (var key in n) {
if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) {
o[key] = n[key];
}
}
return o;
}
function isEmpty(str) {
if (str == undefined || str == null || str == "" || typeof str == 'undefined') {
return true;
}
}
function initContainer(c) {
_container = document.getElementById(c);
}
function initCamera() {
_camera = new THREE.PerspectiveCamera(_fov, window.innerWidth / window.innerHeight, 1, 1100);
_camera.target = new THREE.Vector3(0, 0, 0);
_cameraOrtho = new THREE.OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 1, 10);
_cameraOrtho.position.z = 10;
_scene = new THREE.Scene();
_sceneOrtho = new THREE.Scene();
}
function initRaycaster() {
_raycaster = new THREE.Raycaster();
}
function makePanorama(pRadius, widthSegments, heightSegments, u) {
var mesh = new THREE.Mesh(new THREE.SphereGeometry(pRadius, widthSegments, heightSegments),
new THREE.MeshBasicMaterial(
{ map: THREE.ImageUtils.loadTexture(u) }
));
mesh.scale.x = -1;
_scene.add(mesh);
}
function initRenderer() {
_renderer = new THREE.WebGLRenderer();
_renderer.setSize(window.innerWidth, window.innerHeight);
_renderer.autoClear = false;
_container.appendChild(_renderer.domElement);
}
function onDocumentMouseDown(event) {
event.preventDefault();
_isUserInteracting = true;
_onPointerDownPointerX = event.clientX;
_onPointerDownPointerY = event.clientY;
_onPointerDownLon = _lon;
_onPointerDownLat = _lat;
}
function onDocumentMouseMove(event) {
if (_isUserInteracting) {
_lon = (_onPointerDownPointerX - event.clientX) * 0.1 + _onPointerDownLon;
_lat = (event.clientY - _onPointerDownPointerY) * 0.1 + _onPointerDownLat;
}
}
function onDocumentMouseUp() {
_isUserInteracting = false;
}
function onDocumentMouseClick(event) {
_mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
_mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
_raycaster.setFromCamera(_mouse, _cameraOrtho);
var intersects = _raycaster.intersectObjects(_clickableObjects);
intersects.forEach(this.def.onClick);
}
function onDocumentMouseWheel(ev, minFocalLength, maxFocalLength) {
var ev = ev || window.event;
var down = true;
var m = _camera.getFocalLength();
down = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0;
if (down) {
if (m > minFocalLength) {
m -= m * 0.05
_camera.setFocalLength(m);
}
} else {
if (m < maxFocalLength) {
m += m * 0.05
_camera.setFocalLength(m);
}
}
if (ev.preventDefault) {
ev.preventDefault();
}
return false;
}
function onWindowResize() {
_camera.aspect = window.innerWidth / window.innerHeight;
_camera.projectionMatrix.makePerspective(_fov, _camera.aspect, 1, 1100);
_camera.updateProjectionMatrix();
_cameraOrtho.left = -window.innerWidth / 2;
_cameraOrtho.right = window.innerWidth / 2;
_cameraOrtho.top = window.innerHeight / 2;
_cameraOrtho.bottom = -window.innerHeight / 2;
_cameraOrtho.updateProjectionMatrix();
_renderer.setSize(window.innerWidth, window.innerHeight);
}
function initLable(lables, sprite) {
if (sprite == 'label') {
for (var i = 0; i < lables.length; i++) {
_lables.push(createLableSprite(_sceneOrtho, lables[i].text, lables[i].position));
}
} else if (sprite == 'icon') {
for (var i = 0; i < lables.length; i++) {
_sprites.push(createSprite(lables[i].position, lables[i].logoUrl, lables[i].text));
}
}
}
function createLableSprite(scene, name, position) {
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
var metrics = context1.measureText(name);
var width = metrics.width * 1.5;
context1.font = "10px 宋体";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillRect(0, 0, width + 8, 20 + 8);
context1.fillStyle = "rgba(0,0,0,0.2)";
context1.fillRect(2, 2, width + 4, 20 + 4);
context1.fillStyle = "rgba(255,255,255,0.95)";
context1.fillText(name, 4, 20);
var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture1 });
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(1.0, 1.0, 1.0);
sprite1.position.set(0, 0, 0);
sprite1.name = name;
var lable = {
name: name,
pos: position,
canvas: canvas1,
context: context1,
texture: texture1,
sprite: sprite1
};
_sceneOrtho.add(lable.sprite);
_clickableObjects.push(lable.sprite);
return lable;
}
function createSprite(position, url, name) {
var textureLoader = new THREE.TextureLoader();
var ballMaterial = new THREE.SpriteMaterial({
map: textureLoader.load(url)
});
var sp1 = {
pos: position,
name: name,
sprite: new THREE.Sprite(ballMaterial)
};
sp1.sprite.scale.set(32, 32, 1.0);
sp1.sprite.position.set(0, 0, 0);
sp1.sprite.name = name;
_sceneOrtho.add(sp1.sprite);
_clickableObjects.push(sp1.sprite);
return sp1;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
calPosition();
addSprites();
runRender();
}
function calPosition() {
_lat = Math.max(-85, Math.min(85, _lat));
var phi = THREE.Math.degToRad(90 - _lat);
var theta = THREE.Math.degToRad(_lon);
_camera.target.x = _pRadius * Math.sin(phi) * Math.cos(theta);
_camera.target.y = _pRadius * Math.cos(phi);
_camera.target.z = _pRadius * Math.sin(phi) * Math.sin(theta);
_camera.lookAt(_camera.target);
}
function addSprites() {
if (typeof (_sprites) != "undefined") {
for (var i = 0; i < _sprites.length; i++) {
var wp = geoPosition2World(_sprites[i].pos.lon, _sprites[i].pos.lat);
var sp = worldPostion2Screen(wp, _camera);
var test = wp.clone();
test.project(_camera);
if (test.x > -1 && test.x < 1 && test.y > -1 && test.y < 1 && test.z > -1 && test.z < 1) {
_sprites[i].sprite.scale.set(32, 32, 32);
_sprites[i].sprite.position.set(sp.x, sp.y, 1);
}
else {
_sprites[i].sprite.scale.set(1.0, 1.0, 1.0);
_sprites[i].sprite.position.set(0, 0, 0);
}
}
}
if (typeof (_lables) != "undefined") {
for (var i = 0; i < _lables.length; i++) {
var wp = geoPosition2World(_lables[i].pos.lon, _lables[i].pos.lat);
var sp = worldPostion2Screen(wp, _camera);
var test = wp.clone();
test.project(_camera);
if (test.x > -1 && test.x < 1 && test.y > -1 && test.y < 1 && test.z > -1 && test.z < 1) {
var metrics = _lables[i].context.measureText(_lables[i].name);
var width = metrics.width * 3.5;
_lables[i].sprite.scale.set(400, 150, 1.0);
_lables[i].sprite.position.set(sp.x + width, sp.y - 40, 1);
}
else {
_lables[i].sprite.scale.set(1.0, 1.0, 1.0);
_lables[i].sprite.position.set(0, 0, 0);
}
}
}
}
function geoPosition2World(lon, lat) {
lat = Math.max(-85, Math.min(85, lat));
var phi = THREE.Math.degToRad(90 - lat);
var theta = THREE.Math.degToRad(lon);
var result = {
x: _pRadius * Math.sin(phi) * Math.cos(theta),
y: _pRadius * Math.cos(phi),
z: _pRadius * Math.sin(phi) * Math.sin(theta)
}
return new THREE.Vector3(result.x, result.y, result.z);
}
function worldPostion2Screen(world_vector, camera) {
var vector = world_vector.clone();
vector.project(camera);
var result = {
x: Math.round((vector.x + 1) * window.innerWidth / 2 - window.innerWidth / 2),
y: Math.round(window.innerHeight / 2 - (-vector.y + 1) * window.innerHeight / 2),
z: 0
};
return new THREE.Vector3(result.x, result.y, result.z);
}
function runRender() {
_renderer.clear();
_renderer.render(_scene, _camera);
_renderer.clearDepth();
_renderer.render(_sceneOrtho, _cameraOrtho);
}
var _setContainer;
var _hideImgId = "hideimgid825";
var _himg;
var _cvId = 'cv825';
var _cv;
var _infoId = 'info825';
var _info;
var _lable = [];
var count = 1;
var setOpt = {
container: 'myDiv',//setting容器
imgUrl: 'resources/img/panorama/3.jpg',
width: '',//指定宽度,高度自适应
showGrid: true,//是否显示格网
showPosition: true,//是否显示经纬度提示
lableColor: '#9400D3',//标记颜色
gridColor: '#48D1CC',//格网颜色
lables: [],//标记 {lon:114,lat:38,text:'标记一'}
addLable: true,//开启后双击添加标记 (必须开启经纬度提示)
getLable: true,//开启后右键查询标记 (必须开启经纬度提示)
deleteLbale: true,//开启默认中键删除 (必须开启经纬度提示)
}
function panoramaSetting(opt) {
this.config(opt);
}
panoramaSetting.prototype = {
constructor: this,
def: {},
config: function (opt) {
this.def = extend(setOpt, opt, true);
},
init: function () {
var that = this;
_lable = this.def.lables;
initSetContainer(this.def.container, this.def.imgUrl);
setTimeout(function () {
adptpImg(that.def.width, that.def.imgUrl);
clearCanvas();
if (that.def.showGrid) {
initGrid(that.def.gridColor);
}
if (that.def.showPosition) {
initCursor();
}
initLables(that.def.lables, that.def.lableColor);
var then = that;
if (count == 2) {
if (that.def.addLable) {
_info.addEventListener("dblclick", function (e) {
var text = prompt("标记名称");
if (!isEmpty(text)) {
addMark(e, then.def.lableColor, text);
}
});
}
if (that.def.getLable) {
document.oncontextmenu = function (e) {
e.preventDefault();
};
_info.addEventListener("mousedown", function (e) {
if (e.button == 2) {
var p = selectLable1(e);
if (!isEmpty(p.lon)) {
alert("经度" + p.lon + ",纬度" + p.lat + ",名称" + p.text);
}
}
});
}
if (that.def.deleteLbale) {
_info.addEventListener("mousedown", function (e) {
if (e.button == 1) {
var p = selectLable1(e);
if (!isEmpty(p.lon)) {
var c = confirm("您确认要删除该标记吗?");
if (c) {
removeByValue(_lable, p);
that.clean();
that.init();
}
}
}
});
}
}
}, 100);
count++;
},
getAllLables: function () {
return _lable;
},
addLable: function (e, text) {
var position = addMark(e, this.def.lableColor, text);
},
getLable: function (e) {
return selectLable1(e);
},
listen: function (type, fun) {
_info.addEventListener(type, function (e) {
fun(e);
})
},
delete: function (p) {
if (!isEmpty(p.lon)) {
removeByValue(_lable, p);
}
},
clean: function () {
document.onmousemove = () => { }
document.getElementById(this.def.container).innerHTML = '';
}
}
function initSetContainer(c, url) {
_setContainer = document.getElementById(c);
_himg = document.getElementById(_hideImgId);
if (_himg != null) {
document.body.removeChild(_himg);
}
_himg = document.createElement('img');
_himg.style.visibility = 'hidden';
_himg.id = _hideImgId;
_himg.src = url;
_cv = document.getElementById(_cvId);
if (_cv != null) {
_setContainer.removeChild(_cv);
}
_cv = document.createElement('canvas');
_setContainer.appendChild(_cv);
_cv.id = _cvId;
_info = document.getElementById(_infoId);
if (_info != null) {
document.body.removeChild(_info);
} else {
_info = document.createElement('div');
}
_info.id = _infoId;
_info.style.height = "40px";
_info.style.width = "110px";
_info.style.backgroundColor = "#3C8DBC";
_info.style.display = "none";
_info.style.position = "absolute";
_info.style.filter = "alpha(Opacity=80)";
_info.style.mozOpacity = 0.5;
_info.style.opacity = 0.8;
_info.style.fontFamily = "楷体";
_info.style.fontWeight = "bold";
_info.style.textShadow = "0 0 0.2em #fffd84";
_info.style.textAlign = "center";
document.body.appendChild(_info);
}
function adptpImg(width, url) {
if (!isEmpty(width)) {
_setContainer.style.width = width;
}
_setContainer.style.backgroundImage = '';
var naturalHeight = _himg.naturalHeight;
var naturalWidth = _himg.naturalWidth;
var scale = naturalHeight / naturalWidth;
var height = scale * _setContainer.style.width.split("px")[0];
_setContainer.style.height = height + "px";
setTimeout(function () {
_setContainer.style.backgroundRepeat = 'no-repeat';
_setContainer.style.backgroundPosition = '0% 0%';
_setContainer.style.backgroundSize = 'cover';
_setContainer.style.backgroundImage = "url(" + url + ")";
}, 100);
}
function initGrid(color) {
_cv.width = _setContainer.style.width.split("px")[0];
_cv.height = _setContainer.style.height.split("px")[0];
if (_cv.getContext) {
var ctx = _cv.getContext("2d"),
width = _cv.width,
height = _cv.height;
ctx.strokeStyle = color;
for (var i = 1; i < 19; i++) {
if (i == 9) {
ctx.lineWidth = 3;
} else {
ctx.lineWidth = 0.8;
}
ctx.beginPath();
ctx.moveTo(0, i * height / 18);
ctx.lineTo(width, i * height / 18);
ctx.stroke();
}
for (var j = 1; j < 37; j++) {
if (j == 18) {
ctx.lineWidth = 3;
} else {
ctx.lineWidth = 0.8;
}
ctx.beginPath();
ctx.moveTo(j * width / 36, 0);
ctx.lineTo(j * width / 36, height);
ctx.stroke();
}
}
}
function clearCanvas() {
var ctx = _cv.getContext("2d");
var h = _setContainer.height;
var w = _setContainer.width;
ctx.clearRect(0, 0, w, h);
}
function initCursor() {
var minX = _setContainer.offsetLeft;
var maxX = minX + _setContainer.style.width.split("px")[0];
var minY = _setContainer.offsetTop;
var maxY = minY + _setContainer.style.height.split("px")[0];
document.onmousemove = function (ev) {
var oEvent = ev || event;
var pos = getXY(oEvent);
if (pos.x < maxX && pos.x > minX && pos.y < maxY && pos.y > minY) {
_info.style.display = "block";
_info.style.left = pos.x + "px";
_info.style.top = pos.y + "px";
updateInfoDiv(ev);
} else {
_info.style.display = "none";
}
};
}
function getXY(eve) {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
return { x: scrollLeft + eve.clientX, y: scrollTop + eve.clientY };
}
function updateInfoDiv(e) {
var position = calLonLat(e);
var html = "经度:" + position.lon + "</br>" + "纬度:" + position.lat;
_info.innerHTML = html;
}
function calLonLat(e) {
var h = _setContainer.style.height.split("px")[0];
var w = _setContainer.style.width.split("px")[0];
var ix = _setContainer.offsetLeft;
var iy = _setContainer.offsetTop;
iy = iy + h;
var x = e.clientX;
var y = e.clientY;
var lonS = (x - ix) / w;
var lon = 0;
if (lonS > 0.5) {
lon = -(1 - lonS) * 360;
} else {
lon = 1 * 360 * lonS;
}
var latS = (iy - y) / h;
var lat = 0;
if (latS > 0.5) {
lat = (latS - 0.5) * 180;
} else {
lat = (0.5 - latS) * 180 * -1
}
lon = lon.toFixed(2);
lat = lat.toFixed(2);
return { lon: lon, lat: lat };
}
function initLables(arr, color) {
for (var i in arr) {
var p = arr[i];
var m = getXYByLonLat(p.lon, p.lat);
drawCircle(m.x, m.y);
drawText(m.x, m.y, p.text, color);
}
}
function drawText(x, y, txt, lableColor) {
var canvas = _cv;
var ctx = canvas.getContext("2d");
ctx.font = "bold 20px 楷体";
ctx.fillStyle = lableColor;
ctx.fillText(txt, x, y);
}
function drawCircle(x, y) {
var canvas = _cv;
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#0000ff";
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI, true);
ctx.closePath();
ctx.stroke();
ctx.fill();
ctx.fillStyle = "#ff0000";
ctx.beginPath();
ctx.arc(x, y, 2, 0, 2 * Math.PI, true);
ctx.closePath();
ctx.fill();
}
function getXYByLonLat(lon, lat) {
var x = 0;
var y = 0;
var h = _setContainer.style.height.split("px")[0];
var w = _setContainer.style.width.split("px")[0];
if (lon > 0) {
x = 1 * lon / 180 * 0.5 * w;
} else {
x = (1 + lon / 180) * 0.5 * w + 0.5 * w;
}
if (lat > 0) {
y = (1 - lat / 90) * h * 0.5;
} else {
y = -1 * lat / 90 * 0.5 * h + 0.5 * h
}
return { x: x, y: y }
}
function addMark(e, color, text) {
var pos = getXY(e);
var iX = _setContainer.offsetLeft;
var iY = _setContainer.offsetTop;
var x = pos.x - iX;
var y = pos.y - iY;
drawCircle(x, y);
drawText(x, y, text, color);
var ll = calLonLat(e);
var l = { lon: ll.lon, lat: ll.lat, text: text }
_lable.push(l);
return l;
}
function selectLable1(e) {
var flag = false;
var p;
for (var i = 0; i < _lable.length; i++) {
p = _lable[i];
var m = getXYByLonLat(p.lon, p.lat);
var iX = _setContainer.offsetLeft;
var iY = _setContainer.offsetTop;
var screenX = e.clientX;
var screenY = e.clientY;
var x = screenX - iX;
var y = screenY - iY;
var cx = x - m.x;
var cy = y - m.y;
var distence = Math.sqrt(cx * cx + cy * cy);
if (distence <= 5) {
flag = true;
break;
}
}
if (flag) {
return p;
} else {
return {};
}
}
function removeByValue(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].lon == val.lon && arr[i].lat == val.lat) {
arr.splice(i, 1);
break;
}
}
}
global.tpanorama = tpanorama;
global.tpanoramaSetting = panoramaSetting;
global.tpanoramaSetContainer = _setContainer;
}(window));