前端“量子纠缠”:multipleWindow3dScene 来了

最近前端实现的量子纠缠在网络上火了起来,作者bgstaal的推文:09bf3aa0ed5a32f3209186ca11c948b2.png效果如下:

622bf0c2aec4332be1852b4dd6276c62.gif
量子纠缠

那我们一起来看下什么是量子纠缠,以及前端是如何实现的。

什么是量子纠缠?

在量子力学里,当几个粒子在彼此相互作用后,由于各个粒子所拥有的特性已综合成为整体性质,无法单独描述各个粒子的性质,只能描述整体系统的性质,则称这现象为量子缠结或量子纠缠。量子纠缠是一种奇怪的量子力学现象,处于纠缠态的两个量子不论相距多远都存在一种关联,其中一个量子状态发生改变,另一个的状态会瞬时发生相应改变。

前端如何来实现?

作者bgstaal在github上开源了一个项目,r说明如何使用 Three.js 和 localStorage 在多个窗口中设置3D场景。一起来看下代码如何实现的。

首先,从 Github 上克隆 multipleWindow3dScene 项目:

git clone https://github.com/bgstaal/multipleWindow3dScene.git

接下来,通过 vscode 中的 Live Server, 启动该项目,并在浏览器中打开项目主页 http://127.0.0.1:5500/index.html。效果如下:

04d0cda5e4f5b374f309798ebdcd9858.gif
展示效果

现在我们看下项目目录,如下图所示:3ecfe7f33306502a6340bed5605c5c1e.png

  • index.html:设置 HTML 结构的入口点。

  • main.js:使用 Three.js 初始化 3D 场景,管理窗口的调整大小事件,并根据窗口交互更新场景。

  • three.r124.min.js:用于 3D 图形渲染的 Three.js 库的压缩版本。

  • WindowManager.js:处理多个浏览器窗口的生命周期,包括创建、同步和删除。它使用 localStorage 来维护跨窗口的状态。

index.html

index.html:设置 HTML 结构的入口点,引入了压缩后的three.js以及main.js

<!DOCTYPE html>
<html lang="en">
<head><title>3d example using three.js and multiple windows</title><script type="text/javascript" src="three.r124.min.js"></script><style type="text/css">*{margin: 0;padding: 0;}</style>
</head>
<body><script type="module" src="main.js"></script>
</body>
</html>

下来我们先看下main.js。

main.js

定义了存放3d场景以及时间变量,在网站加载成功,页面可见时,则执行初始化init函数,设置场景,窗口管理器等相关配置。

init函数

init 函数负责设置场景、窗口管理器、调整渲染器大小以适应窗口,并开始渲染循环。

function init () {initialized = true;// add a short timeout because window.offsetX reports wrong values before a short period setTimeout(() => {setupScene();setupWindowManager();resize();updateWindowShape(false);render();window.addEventListener('resize', resize);}, 500) 
}

这里添加了一个定时器,主要是因为window.offsetX在短时间内会返回错误的值。

setupScene函数创建了相机、场景、渲染器和3D世界对象,并将渲染器的DOM元素添加到文档体中。

// 设置场景
function setupScene() {// 创建正交相机camera = new t.OrthographicCamera(0, 0, window.innerWidth, window.innerHeight, -10000, 10000);// 设置相机位置camera.position.z = 2.5;near = camera.position.z - .5;far = camera.position.z + 0.5;// 创建场景scene = new t.Scene();scene.background = new t.Color(0.0);scene.add(camera);// 创建渲染器renderer = new t.WebGLRenderer({ antialias: true, depthBuffer: true });renderer.setPixelRatio(pixR);// 创建对象3Dworld = new t.Object3D();scene.add(world);// 设置渲染器的idrenderer.domElement.setAttribute("id", "scene");// 将渲染器添加到body中document.body.appendChild(renderer.domElement);
}

窗口管理器的设置通过setupWindowManager函数完成,它实例化WindowManager,并定义窗口形状变化和窗口改变的回调函数。

窗口形状变化用于跟踪和反应窗口位置的移动。窗口改变的回调函数用于更新场景中的立方体数量。

// 创建一个WindowManager实例
function setupWindowManager() {windowManager = new WindowManager();// 设置窗口形状改变回调函数windowManager.setWinShapeChangeCallback(updateWindowShape);// 设置窗口改变回调函数windowManager.setWinChangeCallback(windowsUpdated);// here you can add your custom metadata to each windows instance// 在这里,您可以向每个窗口实例添加自定义元数据let metaData = { foo: "bar" };// this will init the windowmanager and add this window to the centralised pool of windows// 这将初始化窗口管理器并将此窗口添加到集中的窗口池中windowManager.init(metaData);// call update windows initially (it will later be called by the win change callback)// 调用updateWindows函数windowsUpdated();
}// 当窗口更新时调用该函数
function windowsUpdated() {// 更新立方体数量updateNumberOfCubes();
}
// 更新立方体数量
function updateNumberOfCubes() {// 获取所有窗口let wins = windowManager.getWindows();// remove all cubes// 移除所有立方体cubes.forEach((c) => {world.remove(c);})// 重新初始化立方体数组cubes = [];// add new cubes based on the current window setup// 根据当前窗口设置添加新的立方体for (let i = 0; i < wins.length; i++) {let win = wins[i];// 设置立方体的颜色let c = new t.Color();c.setHSL(i * .1, 1.0, .5);// 设置立方体的尺寸let s = 100 + i * 50;// 创建立方体let cube = new t.Mesh(new t.BoxGeometry(s, s, s), new t.MeshBasicMaterial({ color: c, wireframe: true }));// 设置立方体的位置cube.position.x = win.shape.x + (win.shape.w * .5);cube.position.y = win.shape.y + (win.shape.h * .5);// 将立方体添加到场景中world.add(cube);cubes.push(cube);}
}// 更新窗口形状函数,easing参数默认为true
function updateWindowShape(easing = true) {// storing the actual offset in a proxy that we update against in the render function// 将当前的偏移量存储在代理中,以便在渲染函数中更新sceneOffsetTarget = { x: -window.screenX, y: -window.screenY };// 如果easing参数为false,则将sceneOffset设置为sceneOffsetTargetif (!easing) sceneOffset = sceneOffsetTarget;
}
render函数

render函数是这段代码的核心,主要是获取当前时间,计算出每个立方体每一帧的动画,来处理窗口的变化,并渲染到页面上。还使用了浏览器的 requestAnimationFrame 方法,让render方法在下一次浏览器重绘之前执行,通常最常见的刷新率是 60hz(每秒 60 个周期/帧),以匹配大多数显示器的刷新率,起到优化动画性能的作用。

// 渲染函数,更新和渲染场景 
function render() {// 获取当前时间let t = getTime();// update the window manager// 更新窗口管理器windowManager.update();// update the scene offset based on the current window manager state// this will create a smooth transition between the current scene offset and the target scene offset// calculate the new position based on the delta between current offset and new offset times a falloff value (to create the nice smoothing effect)let falloff = .05;// 计算场景偏移量sceneOffset.x = sceneOffset.x + ((sceneOffsetTarget.x - sceneOffset.x) * falloff);sceneOffset.y = sceneOffset.y + ((sceneOffsetTarget.y - sceneOffset.y) * falloff);// set the world position to the offset//设置场景偏移量world.position.x = sceneOffset.x;world.position.y = sceneOffset.y;// get the window manager and the window// 获取所有窗口let wins = windowManager.getWindows();// loop through all our cubes and update their positions based on current window positions// 遍历cubes数组,更新立方体的位置for (let i = 0; i < cubes.length; i++) {// 获取cubes数组中的第i个元素let cube = cubes[i];// 获取wins数组中的第i个元素let win = wins[i];// 将t赋值给_tlet _t = t;// + i * .2;let posTarget = { x: win.shape.x + (win.shape.w * .5), y: win.shape.y + (win.shape.h * .5) }// 计算cube当前位置到目标位置的距离,并乘以衰减系数cube.position.x = cube.position.x + (posTarget.x - cube.position.x) * falloff;cube.position.y = cube.position.y + (posTarget.y - cube.position.y) * falloff;// 计算cube的旋转角度cube.rotation.x = _t * .5;cube.rotation.y = _t * .3;};// render the scenerenderer.render(scene, camera);requestAnimationFrame(render);
}
resize函数

resize函数,在浏览器窗口大小改变时,调整渲染器的尺寸以适应窗口大小,相机和渲染器也进行更新调整。

// 调整渲染器的尺寸以适应窗口大小
function resize() {// 获取窗口的宽度let width = window.innerWidth;// 获取窗口的高度let height = window.innerHeight// 创建一个正交相机,参数为:left,right,top,bottom,near,farcamera = new t.OrthographicCamera(0, width, 0, height, -10000, 10000);// 更新相机的投影矩阵camera.updateProjectionMatrix();// 设置渲染器的尺寸renderer.setSize(width, height);
}

接下来看下我们看下WindowManager文件

WindowManager.js

窗口管理器WindowManager函数,主要是监听 localStorage 变化,刷新渲染立方体的位置。其中 localStorage,存储了立方体在浏览器窗口的位置,包含距离屏幕左上角x轴y轴的距离,和浏览器窗口的宽和高这些信息。

我们看下localStorage的信息,如下图所示:c709cddebcedb532dd6710f1fc23bba0.png

通过监听beforeunload事件监听窗口是否关闭,关闭则删除浏览器对应的立方体的信息。

// 当前窗口即将关闭时的事件监听器window.addEventListener('beforeunload', function (e) {// 获取窗口索引let index = that.getWindowIndexFromId(that.#id);//remove this window from the list and update local storage// 从列表中删除此窗口并更新本地存储that.#windows.splice(index, 1);that.updateWindowsLocalStorage();});

窗口管理器的init方法,根据当前窗口的位置,创建当前窗口唯一的id,创建一个立方体的位置数据,存储在localStorage,方便监听,最后执行了windowsUpdated 方法,更新立方体数量,首先通过 getWindows方法,拿到所有立方体的数据,绘制出新的立方体信息。

// initiate current window (add metadata for custom data to store with each window instance)// 初始化当前窗口(添加元数据以将自定义数据存储到每个窗口实例中)init(metaData) {//将本地存储中的windows数据转换为JSON格式,若未存储,则初始化为空数组this.#windows = JSON.parse(localStorage.getItem("windows")) || [];//获取本地存储中的count值,若未存储,则初始化为0this.#count = localStorage.getItem("count") || 0;this.#count++;this.#id = this.#count;//获取窗口形状let shape = this.getWinShape();//将窗口数据赋值给this.#winDatathis.#winData = { id: this.#id, shape: shape, metaData: metaData };//将this.#winData添加到this.#windows数组中this.#windows.push(this.#winData);//将this.#count存储到本地localStorage.setItem("count", this.#count);//更新本地存储中的windows数据this.updateWindowsLocalStorage();}

以上就是主要的核心效果代码。

参考来源

https://github.com/bgstaal/multipleWindow3dScene

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#browser_compatibility

https://zh.wikipedia.org/wiki/%E9%87%8F%E5%AD%90%E7%BA%8F%E7%B5%90

- END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

ae5856646391668944d80e780537ba60.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/203124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据Doris(三十三):Doris高级设置

文章目录 Doris高级设置 一、增大内存

【华为数据之道学习笔记】2-建立企业级数据综合治理体系

数据作为一种新的生产要素&#xff0c;在企业构筑竞争优势的过程中起着重要作用&#xff0c;企业应将数据作为一种战略资产进行管理。数据从业务中产生&#xff0c;在IT系统中承载&#xff0c;要对数据进行有效治理&#xff0c;需要业务充分参与&#xff0c;IT系统确保遵从&…

AWS Remote Control ( Wi-Fi ) on i.MX RT1060 EVK - 2 “架构 AWS”

接续上一章节&#xff0c;我们把开发环境架设好之后&#xff0c;此章节叙述如何建立 AWS IoT 环境&#xff0c;请务必已经有 AWS Account&#xff0c;申请 AWS Account 之流程将不在此说明。 III-1. 登入AWS IoT&#xff0c; 在“管理”>“所有装置”>“实物”下点击“建…

IDEA切换Python虚拟环境

前言 因为之前一直使用的IDEA开发&#xff0c;换到VSCODE之后各种不习惯&#xff0c;特别是DEBUG的操作&#xff0c;特别难受&#xff0c;因此决心换回IDEA 环境配置 已有项目调整 进入Project 选择SDKs&#xff0c;新建Python 配置Conda以及虚拟环境 有就选择一个虚拟环境…

LeetCode-周赛-思维训练-中等难度

第一题 1798. 你能构造出连续值的最大数目 解题思路 我们先抛开原题不看&#xff0c;可以先完成一道简单的题目&#xff0c;假设现在就给你一个目标值X&#xff0c;问你能够构造出从【1~X】的连续整数&#xff0c;最小需要几个数&#xff1f; 贪心假设期望&#xff1a;我们要…

Path Finder for Mac:超越系统的文件管理利器

Path Finder for Mac是一款卓越的文件管理器&#xff0c;它不仅具备基本的文件浏览、打开、复制和移动等操作功能&#xff0c;还引入了一系列强大的特性&#xff0c;使得用户可以更高效地管理和处理文件。 一、强大的预览功能 Path Finder for Mac支持多种文件格式的预览&…

题目分析,高度理解一维二维数组的申请和[]是什么运算符

第0题: 动态申请二维数组并输出非负数和 和负数出现次数 思路:输入数组大小,然后申请内存并不对其初始化,提高速度,传入数据到申请的数组中,判断如果数组中有元素小于0对其进行计数,否则加上非0数最后输出答案,释放内存 第一题: 解答: 运行结果: 思路分析: 创建长度为20的…

RobotFramework编写用例,在Jenkins上如何实现用例的并发运行?

我们了解RobotFramework编写自动化测试用例的方法&#xff0c;了解如何将用例在Jenkins上运行。 但是&#xff0c;随着用例的增多&#xff0c;传统的pybot/robot命令运行测试用例会耗费大量的时间&#xff0c;这就慢慢成为了一个苦恼的问题。 那么&#xff0c;在Jenkins上如何…

JFrog Artifactory二进制文件管理工具部署使用

1.简介 JFrog Artifactory二进制文件管理工具&#xff0c;目前已经在使用的公司有很多&#xff0c;足见他的方便好用。 2.下载安装包 点击下载地址 这里我下载的是7.9.2版本 3. 安装 &#xff08;1&#xff09;在安装JFrog Artifactory之前需要安装好jdk&#xff08;需…

9_企业架构队列缓存中间件分布式Redis

企业架构队列缓存中间件分布式Redis 学习目标和内容 1、能够描述Redis作用及其业务适用场景 2、能够安装配置启动Redis 3、能够使用命令行客户端简单操作Redis 4、能够实现操作基本数据类型 5、能够理解描述Redis数据持久化机制 6、能够操作安装php的Redis扩展 7、能够操作实现…

AWS 日志分析工具

当您的网络资源托管在 AWS 中时&#xff0c;需要定期监控您的 AWS CloudTrail 日志、Amazon S3 服务器日志和 AWS ELB 日志等云日志&#xff0c;以降低任何潜在的安全风险、识别严重错误并确保满足所有合规性法规。 什么是 Amazon S3 Amazon Simple Storage Service&#xff…

苹果ios的系统app应用WebClip免签应用开源及方式原理

在移动设备上&#xff0c;为了方便访问我们经常使用的网站或服务&#xff0c;我们经常会希望将其添加到主屏幕上&#xff0c;以便快速启动。虽然我们可以通过使用浏览器书签实现这一目标&#xff0c;但添加一个图标到主屏幕上&#xff0c;使得它看起来与原生App无异&#xff0c…

为何开展数据清洗、特征工程和数据可视化、数据挖掘与建模?

1.2为何开展数据清洗、特征工程和数据可视化、数据挖掘与建模 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解1.2节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学…

一个最新国内可用的免费GPT4,Midjourney绘画网站+使用教程

一、前言 ChatGPT GPT4.0&#xff0c;Midjourney绘画&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而&#xff0c;GPT-4对普…

MAC 系统在vs code中,如何实现自动换行

目录 问题描述&#xff1a; 问题解决&#xff1a; 问题描述&#xff1a; 在vscode中&#xff0c;有些时候&#xff0c;一行内容过多&#xff0c;如果不能自动换行&#xff0c;就需要拖动页面&#xff0c;才能看到完整的内容。如下图两行所示&#xff1a; 问题解决&#xff1a…

基于opencv和tensorflow实现人脸识别项目源码+可执行文件,采用python中的tkinter库做可视化

项目名称: 基于OpenCv和tensorflow的人脸识别 完整代码下载地址&#xff1a;基于OpenCv和tensorflow的人脸识别 环境配置: Pythontensorflow2OpenCv categories: 人工智能 description: Opencv是一个开源的的跨平台计算机视觉库&#xff0c;内部实现了图像处理和计算机视觉方…

2023 IoTDB 用户大会成功举办,深入洞察工业互联网数据价值

2023 年 12 月 3 日&#xff0c;中国通信学会作为指导单位&#xff0c;Apache IoTDB Community、清华大学软件学院、中国通信学会开源技术委员会联合主办&#xff0c;“科创中国”开源产业科技服务团和天谋科技&#xff08;北京&#xff09;有限公司承办的 2023 IoTDB 用户大会…

基于 Stereo R-CNN 的自动驾驶 3D 目标检测

论文地址&#xff1a;https://openaccess.thecvf.com/content_CVPR_2019/papers/Li_Stereo_R-CNN_Based_3D_Object_Detection_for_Autonomous_Driving_CVPR_2019_paper.pdf 论文代码&#xff1a;https://github.com/HKUST-Aerial-Robotics/Stereo-RCNN 论文背景 大多数 3D 物…

【开源】基于JAVA的APK检测管理系统

项目编号&#xff1a; S 038 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S038&#xff0c;文末获取源码。} 项目编号&#xff1a;S038&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软…

MA营销自动化如何助力商家实现精准营销?

惟客数据 MAP 是一个跨渠道和设备的自动化营销平台&#xff0c;允许接触点编排个性化旅程&#xff0c;通过短信、社交推送等方式为您的客户创建无缝的个性化体验&#xff0c;加强客户关系并赢得忠诚度。可与惟客数据CDP 产品无缝配合使用&#xff0c;通过数据驱动做出更实时&am…