实现跨域iframe的陀螺仪全景图效果

本文探讨了解决跨域iframe中deviceorientation事件无法触发的问题,通过使用postMessage进行父子页面间的数据通信,实现了设备方向数据的有效传递。文章详细介绍了父页面如何监听并发送设备方向数据,以及子页面如何接收和更新这些数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开发时发现同根iframe子页面可以直接检测到deviceorientation事件,但跨域iframe不可以,因此通过postMessage传递信息。

参考:https://stackoverflow.com/questions/37262953/deviceorientation-not-triggering-in-ios-browsers-when-referenced-in-iframe

https://github.com/w3c/deviceorientation/issues/57

将来w3c直接支持子页面deviceorientation事件就更好了。

父页面:

<!DOCTYPE html>
<html>

<head>
    <title>blank</title>
    <script type="text/javascript">
    var onDeviceOrientationChangeEvent = function(event) {
        window.deviceOrientation = event;
    };
    window.addEventListener('message', function(rs) {
        if (rs.data === 'gyroscope') {
            window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
            var nInterval = window.setInterval(function() {
                var val = {
                    "act": "gyroscope",
                    "val": {
                        alpha: window.deviceOrientation.alpha,
                        beta: window.deviceOrientation.beta,
                        gamma: window.deviceOrientation.gamma
                    }
                };
                //获取iframe的id
                var ifr = document.getElementById('mainFrame');
                //iframe的路径
                var url = 'http://172.19.36.50:8083/panorama12/index.html';
                ifr.contentWindow.postMessage(JSON.stringify(val), url);
            }, 67);
        }
    });
    </script>
</head>

<body>
    <iframe id="mainFrame" src="http://172.19.36.50:8083/panorama12/index.html" style="width: 1024px;height:768px;"></iframe>
</body>

</html>

子页面通知父级监听deviceorientation事件处(非必要代码):

if(top !== self) {
    window.parent.postMessage("gyroscope", '*');
}

子页面接受信息处:

window.onmessage = function(event) {
    var data = eval('(' + event.data + ')');
    if (data.act === 'gyroscope') {
        window.deviceOrientation = data.val;
    }
}

three.js里的DeviceOrientationControls.js修改处:

/**
 * @author richt / http://richt.me
 * @author WestLangley / http://github.com/WestLangley
 *
 * W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
 */

THREE.DeviceOrientationControls = function (object) {

	var scope = this;

	this.object = object;
	this.object.rotation.reorder("YXZ");

	this.enabled = true;

	this.deviceOrientation = {};
	this.screenOrientation = 0;

	this.alpha = 0;
	this.alphaOffsetAngle = 0;


	var onDeviceOrientationChangeEvent = function (event) {

		scope.deviceOrientation = event;

	};

	var onScreenOrientationChangeEvent = function () {

		scope.screenOrientation = window.orientation || 0;

	};

	// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''

	var setObjectQuaternion = function () {

		var zee = new THREE.Vector3(0, 0, 1);

		var euler = new THREE.Euler();

		var q0 = new THREE.Quaternion();

		var q1 = new THREE.Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis

		return function (quaternion, alpha, beta, gamma, orient) {

			euler.set(beta, alpha, -gamma, 'YXZ'); // 'ZXY' for the device, but 'YXZ' for us

			quaternion.setFromEuler(euler); // orient the device

			quaternion.multiply(q1); // camera looks out the back of the device, not the top

			quaternion.multiply(q0.setFromAxisAngle(zee, -orient)); // adjust for screen orientation

		}

	} ();

	this.connect = function () {

		onScreenOrientationChangeEvent(); // run once on load

		if (top === self) {
			window.addEventListener('orientationchange', onScreenOrientationChangeEvent, false);
			window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
		}
		else {
		}

		scope.enabled = true;

	};

	this.disconnect = function () {

		window.removeEventListener('orientationchange', onScreenOrientationChangeEvent, false);
		window.removeEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);

		scope.enabled = false;

	};

	this.update = function () {

		if (scope.enabled === false) return;
		if (top !== self) {
			scope.deviceOrientation = window.deviceOrientation;
		}
		else {
		}
		var alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad(scope.deviceOrientation.alpha) + this.alphaOffsetAngle : 0; // Z
		var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad(scope.deviceOrientation.beta) : 0; // X'
		var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad(scope.deviceOrientation.gamma) : 0; // Y''
		var orient = scope.screenOrientation ? THREE.Math.degToRad(scope.screenOrientation) : 0; // O

		setObjectQuaternion(scope.object.quaternion, alpha, beta, gamma, orient);
		this.alpha = alpha;

	};

	this.updateAlphaOffsetAngle = function (angle) {

		this.alphaOffsetAngle = angle;
		this.update();

	};

	this.dispose = function () {

		this.disconnect();

	};

	this.connect();

};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值