'use strict'; (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 onClick() {} }; function tpanorama(opt) { this.render(opt); } tpanorama.prototype = { constructor: this, def: {}, render: function render(opt) { var _this = this; 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', function (e) { onDocumentMouseWheel(e, _this.def.minFocalLength, _this.def.maxFocalLength); }, false); _container.addEventListener('DOMMouseScroll', function (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 config(opt) { this.def = extend(setOpt, opt, true); }, init: function init() { 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 getAllLables() { return _lable; }, addLable: function addLable(e, text) { var position = addMark(e, this.def.lableColor, text); }, getLable: function getLable(e) { return selectLable1(e); }, listen: function listen(type, fun) { _info.addEventListener(type, function (e) { fun(e); }); }, delete: function _delete(p) { if (!isEmpty(p.lon)) { removeByValue(_lable, p); } }, clean: function clean() { document.onmousemove = function () {}; 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 + "
" + "纬度:" + 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);