当前位置: 首页 > news >正文

分享HTML显示2D/3D粒子时钟

效果截图

实现代码

线上体验:three.js+cannon.js Web 3D

<!DOCTYPE html>
<head>
<title>three.js+cannon.js Web 3D</title><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="renderer" content="webkit"><meta name="force-rendering" content="webkit"><meta http-equiv="X-UA-Compatible" content="IE=10,chrome=1"><meta data-rh="true" name="keywords" content="three.js,JavaScript,cannon.js"><meta data-rh="true" name="description" content="three.js+cannon.js Web 3D"><meta data-rh="true" property="og:title" content="THREE.JS and CANNON.JS"><meta data-rh="true" property="og:url" content=""><meta data-rh="true" property="og:description" content="three.js+cannon.js Web 3D"><meta data-rh="true" property="og:image" content=""><meta data-rh="true" property="og:type" content="article"><meta data-rh="true" property="og:site_name" content=""><link rel="icon" href=""><style>.fullscreen {margin: 0px;padding: 0px;width: 100vw;height: 100vh;overflow: hidden;}html, body {overflow: hidden;font-family: '宋体', sans-serif;color: #2f2f2f;}#threeImage{display: none;}</style><script type="importmap">{"imports": {"three": "https://cdn.jsdelivr.net/npm/three@0.162.0/+esm","three/addons/": "https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/","lil-gui": "https://threejsfundamentals.org/3rdparty/dat.gui.module.js","@tweenjs/tween.js": "https://cdn.jsdelivr.net/npm/@tweenjs/tween.js@23.1.1/dist/tween.esm.js","cannonjs": "https://cdn.bootcdn.net/ajax/libs/cannon.js/0.6.2/cannon.min.js"}}</script></head><body class="fullscreen"><div id="threeImage" ><img id="testImage" src=""  crossorigin="anonymous"/></div><canvas></canvas><script type="module">import * as THREE from 'three';import * as TWEEN from '@tweenjs/tween.js';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';import { GUI } from 'lil-gui';import 'cannonjs';let container;let scene, camera, renderer, controls;let NEAR = 0.1, FAR = 1000;let light, ambient, stats, info, mouseX, mouseY;let SHADOW_MAP_WIDTH = 512;let SHADOW_MAP_HEIGHT = 512;let MARGIN = 0;let SCREEN_WIDTH = window.innerWidth;let SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN;//物理世界let world;// 创建默认材质let defaultMaterial = null//创建材质let bMaterial = nulllet cube, tempCubes = new THREE.Object3D();let color = "#12345678";function setup() {setupScene();setupCamera();setupRenderer();setupLights();setPlane();setControls();initCannon();setupEventListeners();animate();addGUI();}function setupScene() {scene = new THREE.Scene();scene.fog = new THREE.Fog( 0x222222, 1000, FAR );scene.background  = new THREE.Color(0xf5e6d3);}function setupCamera() {let res = SCREEN_WIDTH / SCREEN_HEIGHT;camera = new THREE.PerspectiveCamera(45, res, NEAR, FAR);//camera.up.set(0,0,1);//camera.position.set(0,30,20);//camera.position.z = 19;//camera.position.y = -45;camera.position.set(0, 30, 30)//camera.lookAt(0, 0, 0);//camera.lookAt(new THREE.Vector3(0, 0, 0));}let rotWorldMatrix;function rotateAroundWorldAxis(object, axis, radians) {//object:需要旋转的物体,axis:旋转中心轴向量,radians:rotWorldMatrix = new THREE.Matrix4();rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);rotWorldMatrix.multiply(object.matrix);          // pre-multiplyobject.matrix = rotWorldMatrix;object.rotation.setFromRotationMatrix(object.matrix);}function setupRenderer() {renderer = new THREE.WebGLRenderer({ clearColor: 0x000000, clearAlpha: 1, antialias:  true,// 抗锯齿logarithmicDepthBuffer: true // 使用Three进行加载模型时,总会遇到模型相接处或某些区域出现频闪问题或内容被相邻近元素覆盖掉的情况,对数缓存开启可解决,使用对数缓存});renderer.setSize(window.innerWidth, window.innerHeight);//renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );renderer.setClearColor( scene.fog.color, 1 );renderer.autoClear = false;renderer.shadowMapEnabled = true;renderer.shadowMapSoft = true;//开启阴影效果 设置阴影类型// BasicShadowMap 能够给出没有经过过滤的阴影映射 —— 速度最快,但质量最差。// PCFShadowMap 为默认值,使用Percentage-Closer Filtering (PCF)算法来过滤阴影映射。// PCFSoftShadowMap 和PCFShadowMap一样使用 Percentage-Closer Filtering (PCF)算法过滤阴影映射,但在使用低分辨率阴影图时具有更好的软阴影。// VSMShadowMap 使用Variance Shadow Map (VSM)算法来过滤阴影映射。当使用VSMShadowMap时,所有阴影接收者也将会投射阴影renderer.shadowMap.enabled = true;renderer.shadowMap.type = THREE.BasicShadowMaprenderer.shadowMap.autoUpdate = falserenderer.shadowMap.needsUpdate = true// 是否使用传统照明模式,默认为是,关闭传统照明模式即可模仿物理光照,光亮随距离可递减renderer.useLegacyLights = false;// 设置色调映射renderer.toneMapping = THREE.ACESFilmicToneMapping;// 曝光强度renderer.toneMappingExposure = 0.8renderer.outputEncoding = THREE.sRGBEncoding;container = document.createElement( 'div' );document.body.appendChild( container );//document.body.appendChild(renderer.domElement);//renderer.domElement.style.position = "relative";//renderer.domElement.style.top = MARGIN + 'px';container.appendChild( renderer.domElement );}function setPlane(){let planeGeometry = new THREE.PlaneGeometry(60, 20);let planeMaterial = new THREE.MeshBasicMaterial({color: 0xffffff});let plane = new THREE.Mesh(planeGeometry, planeMaterial);// 几何体绕着x轴旋转-90度plane.rotateX(-Math.PI/2);// 设置平面网格为接受阴影的投影面plane.receiveShadow = true;scene.add(plane);}function setupLights() {let ambientLight = new THREE.AmbientLight(0xffffff);ambientLight.castShadow = true;scene.add(ambientLight);// LIGHTSambient = new THREE.AmbientLight( 0xffffff );ambient.castShadow = true;scene.add( ambient );// 添加聚光灯1addSpotlight(50,50,50);// 添加聚光灯2addSpotlight(-50,50,50);// 添加聚光灯3addSpotlight(50,50,-50);// 添加聚光灯4addSpotlight(-50,50,-50);addLight();}function addLight(){light = new THREE.SpotLight( 0xffffff );light.position.set( 30, 30, 30 );light.target.position.set( 0, 0, 0 );light.castShadow = true;light.shadowCameraNear = 10;light.shadowCameraFar = 100;//camera.far;light.shadowCameraFov = 30;light.shadowMapBias = 0.0039;light.shadowMapDarkness = 0.5;light.shadowMapWidth = SHADOW_MAP_WIDTH;light.shadowMapHeight = SHADOW_MAP_HEIGHT;light.shadowCameraVisible = true;scene.add( light );}function setupEventListeners() {window.addEventListener("resize", onWindowResize);}function onDocumentMouseMove( event ) {mouseX = ( event.clientX - windowHalfX );mouseY = ( event.clientY - windowHalfY );}function onWindowResize( event ) {SCREEN_WIDTH = window.innerWidth;SCREEN_HEIGHT = window.innerHeight;renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );//camera.aspect = window.innerWidth / window.innerHeight;//renderer.setSize(window.innerWidth, window.innerHeight);camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;camera.updateProjectionMatrix();//controls.screen.width = SCREEN_WIDTH;//controls.screen.height = SCREEN_HEIGHT;camera.radius = ( SCREEN_WIDTH + SCREEN_HEIGHT ) / 4;}//let clock = new THREE.Clock()function render () {renderer.clear();renderer.render(scene, camera);controls.update();//let delta = clock.getDelta()//world.step(delta)// 更新物理世界 step ( dt , [timeSinceLastCalled] , [maxSubSteps=10] )// dt:固定时间戳(要使用的固定时间步长)// [timeSinceLastCalled]:自上次调用函数以来经过的时间// [maxSubSteps=10]:每个函数调用可执行的最大固定步骤数// * 设置更新物理世界world的步长timestep//  * 这里选用60Hz的速度,即1.0 / 60.0world.step(1.0 / 60.0)//world.fixedStep()}function animate() {render();requestAnimationFrame(animate);}function addTexture(url){// 加载纹理const textureLoader = new THREE.TextureLoader()const texture = textureLoader.load(url)//textureLoader.load(url, (texture) => {//  texture.mapping = THREE.EquirectangularReflectionMapping//  scene.background = texture//  scene.environment = texture//  // 背景模糊强度//  scene.backgroundBlurriness = 0.01//})return texture}function setControls(){controls = new OrbitControls( camera, renderer.domElement );controls.enableDamping = true;controls.rotateSpeed = 1.0;controls.zoomSpeed = 1.2;controls.panSpeed = 0.2;controls.noZoom = false;controls.noPan = false;controls.staticMoving = false;controls.dynamicDampingFactor = 0.3;const radius = 10;controls.minDistance = 0.0;controls.maxDistance = radius * 10;controls.enablePan = truecontrols.dampingFactor = 0.25controls.screenSpacePanning = falsecontrols.enableZoom = truecontrols.zoomScale = 10controls.minZoom = 1controls.maxZoom = 100//controls.minPolarAngle = 1 * -Math.PI / 180//controls.maxPolarAngle = 90 * Math.PI / 180//controls.minAzimuthAngle = 90 * -Math.PI / 180//controls.maxAzimuthAngle = 90 * Math.PI / 180//controls.keys = [ 65, 83, 68 ]; // [ rotateKey, zoomKey, panKey ]//controls.screen.width = SCREEN_WIDTH;//controls.screen.height = SCREEN_HEIGHT;/*// Trackball controlscontrols = new THREE.TrackballControls( camera, renderer.domElement );controls.rotateSpeed = 1.0;controls.zoomSpeed = 1.2;controls.panSpeed = 0.2;controls.noZoom = false;controls.noPan = false;controls.staticMoving = false;controls.dynamicDampingFactor = 0.3;var radius = 100;controls.minDistance = 0.0;controls.maxDistance = radius * 1000;//controls.keys = [ 65, 83, 68 ]; // [ rotateKey, zoomKey, panKey ]controls.screen.width = SCREEN_WIDTH;controls.screen.height = SCREEN_HEIGHT;*/}function addSpotlight (x,y,z){const spotLight2 = new THREE.SpotLight(0xffffff, 1)spotLight2.position.set(x, y, z)spotLight2.target.position.set( 0, 0, 0 )spotLight2.castShadow = truespotLight2.shadow.camera.near = 0.1spotLight2.shadow.camera.far = 30spotLight2.shadow.camera.fov = 30spotLight2.shadow.mapSize.width = 256spotLight2.shadow.mapSize.height = 256// 设置灯光 bias ,解决自阴影问题spotLight2.shadow.bias = -0.0008spotLight2.power = 1scene.add(spotLight2)// 使用辅助器对灯光和阴影进行调整//const cameraHelper = new THREE.SpotLightHelper(spotLight2)//scene.add(cameraHelper)}function initCannon() {// 初始化物理世界world = new CANNON.World()// 设置物理世界重力加速度 单位:m/s² 重力加速度x、y、z分量值,假设y轴竖直向上,这样重力就速度就是y方向负方向。world.gravity.set(0, -9.82, 0)// npm install cannon-es-debugger// 加入 cannon-es-debugger 可以展示模型的物理世界的轮廓// scene: 场景// 物理世界// 第三个参数为可选参数,其中的的onInit方法返回场景中的每个刚体和对应的物理世界的轮廓的three mesh// const cannonDebugger = CannonDebugger(scene, world)// const cannonDebugger = CannonDebugger(scene, world, {//   onInit(body: CANNON.Body, mesh: THREE.Mesh) {//     // //     mesh.visible = true//     console.log(body);//   },// })// 还要在每帧更新调用中更新    Update the CannonDebugger meshes//  cannonDebugger.update() // 创建默认材质defaultMaterial = new CANNON.Material('default')//创建足球材质bMaterial = new CANNON.Material('bMaterial')// 定义两种材质之间的摩擦因数和弹力系数 设置地面材质和小球材质之间的碰撞反弹恢复系数const defaultContactMaterial = new CANNON.ContactMaterial(defaultMaterial, bMaterial, {friction: 5,restitution: 0.5, //反弹恢复系数})// 把关联的材质添加到物理世界中world.addContactMaterial(defaultContactMaterial)// NaiveBroadphase Cannon 默认的算法。检测物体碰撞时,一个基础的方式是检测每个物体是否与其他每个物体发生了碰撞// GridBroadphase 网格检测。轴对齐的均匀网格 Broadphase。将空间划分为网格,网格内进行检测。// SAPBroadphase(Sweep-and-Prune) 扫描-剪枝算法,性能最好。// 默认为 NaiveBroadphase,建议替换为 SAPBroadphase// 碰撞算法world.broadphase = new CANNON.SAPBroadphase(world)//world.broadphase = new CANNON.NaiveBroadphase();// 创建一个物理世界的平面const planeShape = new CANNON.Plane()// 创建一个刚体const planeBody = new CANNON.Body({mass: 0, // 设置质量为0,不受碰撞的影响shape: planeShape,position: new CANNON.Vec3(0, 1, 0)})// 改变平面默认的方向,法线默认沿着z轴,旋转到平面向上朝着y方向// 设置刚体旋转(设置旋转X轴)旋转规律类似threejs 平面planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)// 将刚体添加到物理世界当中world.addBody(planeBody)const textureLoader = new THREE.TextureLoader();let texture = textureLoader.load('https://ts2.cn.mm.bing.net/th?id=OJ.nhM9wE4TnIlRRg');texture.wrapS = THREE.RepeatWrapping;texture.wrapT = THREE.RepeatWrapping;texture.repeat.set(1,1);texture.needsPMREMUpdate = truetexture.minFilter = THREE.LinearFiltertexture.magFilter = THREE.LinearFilterscene.environment = texture;let cubeGeometry = new THREE.BoxGeometry(1,1,1);// http://www.webgl3d.cn/pages/21003f/ PBR材质金属度、粗糙度以及环境贴图const cMaterial = new THREE.MeshPhysicalMaterial({ map: texture,side: THREE.DoubleSide,normalMap: texture,normalScale: new THREE.Vector2(1.1,1.1),specularMap: texture,specular: 0xffffff,shininess: 10,envMap: texture,color: color, metalness: 0.5,//像金属的程度, 非金属材料,如木材或石材,使用0.0,金属使用1.0。roughness: 0.5,//模型表面的光滑或者说粗糙程度,越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱,更多地表现为漫反射。 clearcoat: 1,clearcoatRoughness: 0.01,envMapIntensity: 2.5,opacity: 0.5,transparent: true });cube = new THREE.Mesh(cubeGeometry,cMaterial);cube.position.x=0;cube.position.y=2;cube.position.z=0;cube.castShadow = true;scene.add(cube);}const calcMeshCenter = (group)=>{/*** 包围盒全自动计算:模型整体居中*/let box3 = new THREE.Box3()// 计算层级模型group的包围盒// 模型group是加载一个三维模型返回的对象,包含多个网格模型box3.expandByObject(group)// 计算一个层级模型对应包围盒的几何体中心在世界坐标中的位置let center = new THREE.Vector3()box3.getCenter(center)// console.log('查看几何体中心坐标', center);// 重新设置模型的位置,使之居中。group.position.x = group.position.x - center.xgroup.position.y = group.position.y - center.ygroup.position.z = group.position.z - center.z}const gui = new GUI({width: 280,title: 'Setting',autoPlace: true})var params = new function() {this.color = 0x123456;this.position = -35;this.visible = true;};function addGUI(){gui.addColor(params, "color").onChange(e => {cube.material.color.set(e);});gui.add(params, "position", -172, 28).onChange(e => {tempCubes.position.x = e});}const canvas = document.querySelector('canvas');const ctx = canvas.getContext('2d',{//频繁读取画布信息willReadFrequently: true});function initCanvasSize(){//canvas绘制的图形是位图,即栅格图像或点阵图像,当将它渲染到高清屏时,会被放大,每个像素点会用devicePixelRatio的平方个物理像素点来渲染,因此图片会变得模糊。//将画布尺寸设置为画板尺寸的window.devicePixelRatio倍canvas.width = window.innerWidth * window.devicePixelRatio;canvas.height = "150"//window.innerHeight * window.devicePixelRatio;}initCanvasSize();//获取[min,max]范围内的随机数function getRandom(min, max){return Math.floor(Math.random()*(max+1-min)+min);}//通过构造函数生成圆形颗粒class Particle{constructor(){//生成圆圈的半径const r = Math.min(canvas.width,canvas.height)/2;//画布的中心点const cx = canvas.width/2;const cy = canvas.height/2;//大圆上的随机角度并换算成弧度const rad = getRandom(0,360)*(Math.PI/180); //粒子的坐标this.x = cx + r*Math.cos(rad);this.y = cy + r*Math.sin(rad);//粒子的尺寸this.size = getRandom(1*window.devicePixelRatio,5*window.devicePixelRatio);}randomHexColor() { //随机生成十六进制颜色const hex = Math.floor(Math.random() * 16777216).toString(16); //生成ffffff以内16进制数while (hex.length < 6) { //while循环判断hex位数,少于6位前面加0凑够6位hex = '0' + hex;}return '#' + hex; //返回‘#'开头16进制颜色}draw(){ctx.beginPath();ctx.fillStyle = color;//ctx.fillStyle = this.randomHexColor();ctx.arc(this.x,this.y,this.size,0,2*Math.PI);ctx.fill();}moveTo(targetX,targetY){//设定一个缓动时间 500 ms毫秒//起始位置const startX = this.x;const startY = this.y;const duration = 500;//横向速度 目标位置 减去 当前位置 再除以运动的时间const xSpeed = (targetX - startX)/duration;//纵向速度 目标位置 减去 当前位置 再除以运动的时间const ySpeed = (targetY - startY)/duration;//起始时间const startTime = Date.now();//增加动画效果const _move = ()=>{//运动时间const t = Date.now() - startTime;//x方向运动距离 起始位置 加 速度乘以时间const x = startX + xSpeed * t;//y方向运动距离 起始位置 加 速度乘以时间const y = startY + ySpeed * t;//x,y缓动this.x = x;this.y = y;//超过设定时间取消运动if(t>=duration){// 赋值为目标位置this.x = targetXthis.y = targetY}//重新注册rafrequestAnimationFrame(_move)}//执行移动_move();}}//点数据组const partciles = [];//需要绘制的文本let text = null;//填充点数据for(let i = 0;i<1;i++){//画单个点const p = new Particle();//启动绘制//p.draw();//添加进数组partciles.push(p);}//清空画布function clear(){//清空画布ctx.clearRect(0,0,canvas.width,canvas.height);tempCtx.clearRect(0,0,tempCanvas.width,tempCanvas.height);// 将缓存 canvas 复制到旧的 canvas//ctx.drawImage(tempCanvas,0,0,canvas.width,canvas.height);}// 新建一个 canvas 作为缓存 canvasconst tempCanvas = document.createElement('canvas');// 设置缓冲画布的宽高tempCanvas.width = canvas.width; tempCanvas.height = canvas.height;const tempCtx = tempCanvas.getContext('2d');//绘制function draw(){//在每次绘制文本之前清空画布clear();// 开始绘制//let img = document.createElement('img');//let data = canvas.toDataURL();//img.src = data;// 缓存 canvas 绘制完成//tempCtx.drawImage(img,0,0);update();//遍历数组中的所有点partciles.forEach((p)=>{//绘制点p.draw();//p.moveTo(0,0);})//下一次绘制时注册RAF,重新绘制requestAnimationFrame(draw);}//生成文字function getText(){//得到当前时间 并做截取return new Date().toTimeString().substring(0,8);}//绘制文字function update(){//获得文本const newText = getText();if(newText ==  text){//相同就不绘制return;}text = newText;//绘制 文本const { width, height } = tempCanvas;if(drImage){// let temp = localStorage.getItem("threeImage");// CSSImageValue 或 HTMLCanvasElement 或 HTMLImageElement 或 HTMLVideoElement 或 ImageBitmap 或 OffscreenCanvas 或 SVGImageElement 或 VideoFrame//tempCtx.drawImage(document.getElementById("testImage"),0,0,tempCanvas.width,tempCanvas.height);tempCtx.fillStyle = "#000";tempCtx.textBaseline = "middle";tempCtx.font = `${100*window.devicePixelRatio}px '华文细黑', sans-serif`;//计算出绘制出的文本的宽度const textWidth = tempCtx.measureText(text).width;tempCtx.fillText(text,(width - textWidth)/3,height/2);//imageBox.appendChild(tempCanvas);}//拿到画布上黑色像素点的坐标const points = getPoints();//console.log(points);//如果数组长度小于文本坐标的长度 删除多余部分即可if(points.length < partciles.length){partciles.splice(points.length);}scene.remove(tempCubes); // 更新前删除旧数码显示tempCubes = null;tempCubes = new THREE.Object3D();for(let i=0;i<points.length;i++){let p = partciles[i];//粒子不足创建即可if(!p){p = new Particle();partciles.push(p);}const [x,y] = points[i];p.moveTo(x,y);let tempCube = cube.clone();tempCube.position.set((x/10),(y/10),(y/10));tempCubes.add(tempCube);}if(tempCubes){//calcMeshCenter(tempCubes);rotateAroundWorldAxis(tempCubes,new THREE.Vector3(1,0,0), Math.PI);tempCubes.position.set(-36,10,0);tempCubes.rotateX(-Math.PI/2);tempCubes.scale.set(0.5, 0.5, 0.5);//flipMesh(tempCubes);let position = new THREE.Vector3();let quaternion = new THREE.Quaternion();let scale = new THREE.Vector3();tempCubes.matrixWorld.decompose( position, quaternion, scale );tempCubes.updateMatrixWorld( true );scene.add(tempCubes);}}function flipMesh(object3D) {object3D.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));reverseWindingOrder(object3D);}function reverseWindingOrder(object3D) {// TODO: Something is missing, the objects are flipped alright but the light reflection on them is somehow brokenif (object3D.type === "Mesh") {var geometry = object3D.geometry;for (var i = 0, l = geometry.faces.length; i < l; i++) {var face = geometry.faces[i];var temp = face.a;face.a = face.c;face.c = temp;}var faceVertexUvs = geometry.faceVertexUvs[0];for (i = 0, l = faceVertexUvs.length; i < l; i++) {var vector2 = faceVertexUvs[i][0];faceVertexUvs[i][0] = faceVertexUvs[i][2];faceVertexUvs[i][2] = vector2;}geometry.computeFaceNormals();geometry.computeVertexNormals();}if (object3D.children) {for (var j = 0, jl = object3D.children.length; j < jl; j++) {reverseWindingOrder(object3D.children[j]);}}}function getPoints(){// 得到画布上制定范围内的像素点信息const { width, height, data} = tempCtx.getImageData(0,0,tempCanvas.width,tempCanvas.height);//console.log(data);const points = [];//像素点取稀释点const gap = 4;for(let i = 0; i< width;i+=gap){for(let j = 0; j< height;j+=gap){//通过行号、列号 计算像素点的下标const index = (i+j*width)*4;const r = data[index];const g = data[index+1];const b = data[index+2];const a = data[index+3];//判断是否透明if(r===0&&g===0&&b===0&&a===255){//console.log(r,g,b,a);points.push([i,j])}}}return points;}let imageBox = document.getElementById('threeImage')const loadImage = (url) => {return new Promise((resolve, reject) => {const img = new Image()img.onload = () => {resolve(img);}img.onerror = (err) => {reject(err)}img.src = urlimg.alt = "threeImage";})}function startDownload(url) {document.getElementById("testImage").src = url;document.getElementById("testImage").width = window.innerWidthdocument.getElementById("testImage").height = window.innerHeightloadImage(url).then((resImage)=>{imageReceived(resImage)}).catch((err)=>{throw new Error(err); // reject promise});//let imageURL = url;//let imageDescription = "three image";//downloadedImg = new Image();//downloadedImg.crossOrigin = "Anonymous";//downloadedImg.addEventListener("load", imageReceived, false);//downloadedImg.alt = imageDescription;//downloadedImg.src = imageURL;}let drImage = nullfunction imageReceived(downloadedImg) {const c = document.createElement("canvas");let context = c.getContext("2d");c.width = window.innerWidth || downloadedImg.width;c.height = window.innerHeight || downloadedImg.height;c.innerText = downloadedImg.alt;//downloadedImg.setAttribute('crossOrigin', 'anonymous');//context.drawImage(downloadedImg, 0, 0, c.width, c.height);//imageBox.appendChild(c);//确保图片被加载完成 使用drawImage绘制到画布上面drImage = downloadedImg; //画布已被跨域数据污染的操作try {localStorage.setItem("threeImage", c.toDataURL("image/png"));draw();// 复杂问题拆解成简单化问题// 画单个点,画很多个点,画很多个运动的点// 提升代码掌控能力,开发思维} catch (err) {console.error(`Error: ${err}`);}}//需要服务器端支持 CORS policy: No 'Access-Control-Allow-Origin' startDownload('https://ts2.cn.mm.bing.net/th?id=OJ.nhM9wE4TnIlRRg');setup();</script></body></html>

相关文章:

分享HTML显示2D/3D粒子时钟

效果截图 实现代码 线上体验&#xff1a;three.jscannon.js Web 3D <!DOCTYPE html> <head> <title>three.jscannon.js Web 3D</title><meta charset"utf-8"><meta name"viewport" content"widthdevice-width,ini…...

Java——IDEA使用

一、IDEA介绍 IntelliJ IDEA 是 JetBrains 公司开发的一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于 Java 编程语言&#xff0c;但也支持多种其他语言和框架。由于其强大的功能和灵活性&#xff0c;IntelliJ IDEA 被广泛应用于软件开发领域&…...

高性能STL库 EASTL 、高性能JSON库

GitHub - electronicarts/EASTL: EASTL stands for Electronic Arts Standard Template Library. It is an extensive and robust implementation that has an emphasis on high performance. 兄弟们&#xff0c;对STL要求性能高的可以试试这个EASTL库&#xff01;&#xff01…...

多通道采集器采样接口设计[进行中...]

1.技术问题 这是一个非常小的设计&#xff0c;完全不值得把它展示出来。但是因为这个接口设计关系到一些细微的配置和技术限制&#xff0c;仍然有一些细节需要处理&#xff0c;并且很容易出错&#xff0c;我们先把技术问题罗列一下&#xff1a; 多个传感器对应的多个逻辑通道…...

rapidjson使用中crash问题分析

问题 在使用rapidjson时&#xff0c;使用Document的Parse方法解析json字符串&#xff0c;程序crash。 分析 可以参考https://github.com/Tencent/rapidjson/issues/1269&#xff0c;由于rapidjson的内存分配器默认认为内存分配成功&#xff0c;没有对分配后做判空判断&#…...

TCP协议中的三次握手和四次挥手机制

TCP协议中的三次握手和四次挥手机制 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的通信协议&#xff0c;它的三次握手和四次挥手机制是建立和断开连接的关键步骤。 三次握手&#xff1a; 第一次…...

Linux双网卡默认路由的metric设置不正确,导致SSH连接失败问题定位

测试环境 VMware虚拟机 RockyLinux 9 x86_64 双网卡&#xff1a;eth0(访问外网): 10.206.216.92/24; eth1(访问内网) 192.168.1.4/24 问题描述 虚拟机重启后&#xff0c;SSH连接失败&#xff0c;提示"Connection time out"&#xff0c;重启之前SSH连接还是正常的…...

Batch入门学习:从零开始掌握批处理脚本

目录 1. Batch脚本简介 1.1 什么是Batch脚本&#xff1f; 1.2 Batch脚本的历史 1.3 Batch脚本的应用场景 2. Batch脚本基本语法 2.1 注释 2.2 变量 2.3 常用命令 2.3.1 ECHO 2.3.2 PAUSE 2.3.3 CLS 2.3.4 GOTO 2.3.5 IF 2.3.6 FOR 2.4 参数传递 2.5 输入输出重…...

diffusion model(十八):diffusion model中negative prompt的工作机制

info个人博客主页http://myhz0606.com/article/ncsn 前置阅读&#xff1a; DDPM&#xff1a; http://myhz0606.com/article/ddpm classifier-guided&#xff1a;http://myhz0606.com/article/guided classifier-free guided&#xff1a;http://myhz0606.com/article/classi…...

Python | Leetcode Python题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; class Solution:def dfs(self, grid, r, c):grid[r][c] 0nr, nc len(grid), len(grid[0])for x, y in [(r - 1, c), (r 1, c), (r, c - 1), (r, c 1)]:if 0 < x < nr and 0 < y < nc and grid[x][y] "1":self.d…...

利用圆上两点和圆半径求解圆心坐标

已知圆上两点P1&#xff0c;P2&#xff0c;坐标依次为 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1​,y1​),(x2​,y2​)&#xff0c;圆的半径为 r r r&#xff0c;求圆心的坐标。 假定P1&#xff0c;P2为任意两点&#xff0c;则两点连成线段的中点坐标是 x m i …...

从ChatGPT代码执行逃逸到LLMs应用安全思考

摘要 11月7日OpenAI发布会后&#xff0c;GPT-4的最新更新为用户带来了更加便捷的功能&#xff0c;包括Python代码解释器、网络内容浏览和图像生成能力。这些创新不仅开辟了人工智能应用的新境界&#xff0c;也展示了GPT-4在处理复杂任务方面的惊人能力。然而&#xff0c;与所有…...

Python入门-基础知识-变量

1.标识符与关键字 Python语言规定&#xff0c;标识符由字母、数字和下画线组成&#xff0c;且不允许以数字开头。合法的标识符可以 是student_1、 addNumber、num等&#xff0c;而3number、2_student等是不合法的标识符。在使用标识符时应注意以下几点。 (1)命名时应遵循见名知…...

设计模式原则——接口隔离原则

设计模式原则 设计模式示例代码库地址&#xff1a; https://gitee.com/Jasonpupil/designPatterns 接口隔离原则 要求程序员尽量将臃肿庞大的接口拆分为更小的和更具体的接口&#xff0c;让接口中只包含客户感兴趣的方法接口隔离原则的目标是降低类或模块之间的耦合度&…...

MySQL数据库——在Centos7环境安装

MySQL在Centos7环境安装 1.切换root用户 安装与卸载中&#xff0c;用户全部切换成为root&#xff0c;安装好后&#xff0c;普通用户也能使用 2.卸载不要的环境 要将自己环境中有关mysql的全都删除&#xff0c;避免安装过程中被影响 ps axj | grep mariadb 先检查是否有mari…...

怎样规避液氮容器内部结霜的问题

液氮容器内部结霜问题一直是我们在使用液氮储存罐时遇到的一个棘手难题。液氮的极低温度使得容器内部很容易产生结霜现象&#xff0c;这不仅影响了容器的正常使用&#xff0c;还可能对内部样品或设备造成损坏。因此&#xff0c;如何有效规避液氮容器内部结霜问题成为了每个使用…...

冶金工业5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

冶金工业5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。传统生产方式难以满足现代冶金工业的发展需求&#xff0c;数字化转型成为必然趋势。通过引入5G、工业物联网和数字孪生等先进技术&#xff0c;冶金工业可以实现生产过程智能化、高效化和绿色化&#…...

一文入门机器学习参数调整实操

作者前言: 通过向身边的同事大佬请教之后&#xff0c;大佬指点我把本文的宗旨从“参数调优”改成了“参数调整”。实在惭愧&#xff0c;暂时还没到能“调优”的水平&#xff0c;本文只能通过实操演示“哪些操作会对数据训练产生影响”&#xff0c;后续加深学习之后&#xff0c;…...

基于51单片机的银行排队呼叫系统设计

一.硬件方案 本系统是以排队抽号顺序为核心&#xff0c;客户利用客户端抽号&#xff0c;工作人员利用叫号端叫号&#xff1b;通过显示器及时显示当前所叫号数&#xff0c;客户及时了解排队信息&#xff0c;通过合理的程序结构来执行排队抽号。电路主要由51单片机最小系统LCD12…...

JXCategoryView的使用总结

一、初始化 -(JXCategoryTitleView *)categoryView{if (!_categoryView) {_categoryView [[JXCategoryTitleView alloc] init];_categoryView.delegate self;_categoryView.titleDataSource self;_categoryView.averageCellSpacingEnabled NO; //是否平均分配项目之间的间…...

Centos9 安装VBox增强功能问题

安装步骤 更新gcc 首先手动更新gcc&#xff0c;防止无法兼容最新版本的内核&#xff0c;我这里将gcc 11更新到gcc 13 1.首先更新当前gcc和支持 yum install -y gcc gcc-c 2.下载新版本gcc压缩包 wget http://ftp.gnu.org/gnu/gcc/gcc-13.1.0/gcc-13.1.0.tar.gz 解压到usr ta…...

【JVM】Java虚拟机运行时数据分区介绍

JVM 分区&#xff08;运行时数据区域&#xff09; 文章目录 JVM 分区&#xff08;运行时数据区域&#xff09;前言1. 程序计数器2. Java 虚拟机栈3. 本地方法栈4. Java 堆5. 方法区6. 运行时常量池7. 直接内存 前言 之前在说多线程的时候&#xff0c;提到了JVM虚拟机的分区内存…...

大数据面试题之Kafka(2)

目录 Kafka的工作原理? Kafka怎么保证数据不丢失&#xff0c;不重复? Kafka分区策略 Kafka如何尽可能保证数据可靠性? Kafka数据丢失怎么处理? Kafka如何保证全局有序? 生产者消费者模式与发布订阅模式有何异同? Kafka的消费者组是如何消费数据的 Kafka的…...

前端面试题(基础篇十一)

一、DOCTYPE 的作用是什么&#xff1f; <!DOCTYPE> 声明一般位于文档的第一行&#xff0c;它的作用主要是告诉浏览器以什么样的模式来解析文档。一般指定了之后会以标准模式来进行文档解析&#xff0c;否则就以兼容模式进行解析。在标准模式下&#xff0c;浏览器的解析规…...

【论文阅读】Answering Label-Constrained Reachability Queries via Reduction Techniques

Cai Y, Zheng W. Answering Label-Constrained Reachability Queries via Reduction Techniques[C]//International Conference on Database Systems for Advanced Applications. Cham: Springer Nature Switzerland, 2023: 114-131. Abstract 许多真实世界的图都包含边缘标签…...

Git Flow 工作流学习要点

Git Flow 工作流学习要点 Git Flow — 流程图Git Flow — 操作指令优点&#xff1a;缺点&#xff1a;Git Flow 分支类型Git Flow 工作流程简述关于 feature 分支关于 Release 分支关于 hotfix 分支 总结 Git Flow — 流程图 图片来源&#xff1a;https://nvie.com/posts/a-succ…...

blender 快捷键 常见问题

一、快捷键 平移视图&#xff1a;Shift 鼠标中键旋转视图&#xff1a;鼠标中键缩放视图&#xff1a;鼠标滚动框选放大模型&#xff1a;Shift B线框预览和材质预览切换&#xff1a;Shift Z 二、常见问题 问题&#xff1a;导入模型成功&#xff0c;但是场景中看不到。 解…...

HTTP详解:TCP三次握手和四次挥手

一、TCP协议概述 TCP协议是互联网协议栈中传输层的核心协议之一&#xff0c;它提供了一种可靠的数据传输方式&#xff0c;确保数据包按顺序到达&#xff0c;并且没有丢失或重复。TCP的主要特点包括&#xff1a; 面向连接&#xff1a;TCP在传输数据之前需要建立连接。可靠传输&…...

详解HTTP:有了HTTP,为何需要WebSocket?

在日常生活中&#xff0c;HTTP 常用于请求数据。例如&#xff0c;当你打开一个天气预报网站时&#xff0c;浏览器会发送一个 HTTP 请求到服务器&#xff0c;请求当前的天气数据&#xff0c;服务器返回响应&#xff0c;浏览器解析并显示这些数据。 但是&#xff0c;当涉及到需要…...

Spring Boot 启动流程是怎么样的

引言 SpringBoot是一个广泛使用的Java框架&#xff0c;旨在简化基于Spring框架的应用程序的开发过程。在这篇文章中&#xff0c;我们将深入探讨SpringBoot应用程序的启动流程&#xff0c;了解其背后的机制。 Spring Boot 启动概览 SpringBoot应用程序的启动通常从一个包含 m…...

【学习笔记】数据结构(三)

栈和队列 文章目录 栈和队列3.1 栈 - Stack3.1.1 抽象数据类型栈的定义3.1.2 栈的表示和实现 3.2 栈的应用举例3.2.1 数制转换3.2.2 括号匹配的检验3.2.3 迷宫求解3.2.4 表达式求值 - 波兰、逆波兰3.2.5 反转一个字符串或者反转一个链表 3.3 栈与递归的实现3.4 队列 - Queue3.4…...

学习python笔记:10,requests,enumerate,numpy.array

requests库&#xff0c;用于发送 HTTP 请求的 Python 库。 requests 是一个用于发送 HTTP 请求的 Python 库。它使得发送 HTTP 请求变得简单且人性化。以下是一些基本的 requests 函数及其用途&#xff1a; requests.get(url, **kwargs) 发送一个 GET 请求到指定的 URL。 i…...

经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2)

经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2) 2022 年 11 月&#xff0c;ChatGPT 成功面世&#xff0c;成为历史上用户增长最快的消费者应用。与 Google、FaceBook等公司不同&#xff0c;OpenAI 从初代模型 GPT-1 开始&#xff0c;始终贯彻只有解码器&#xff0…...

MySQL库与表的操作

目录 一、登录并进入数据库 1、登录 2、USE 命令 检查当前数据库 二、库的操作 1、创建数据库语法 2、举例演示 3、退出 三、字符集和校对规则 1、字符集&#xff08;Character Set&#xff09; 2、校对集&#xff08;Collation&#xff09; 总结 3、操作命令 …...

TTS 语音合成技术学习

TTS 语音合成技术 TTS&#xff08;Text-to-Speech&#xff0c;文字转语音&#xff09;技术是一种能够将文字内容转换为自然语音的技术。通过 TTS&#xff0c;机器可以“说话”&#xff0c;这大大增强了人与机器之间的互动能力。无论是在语音助手、导航系统还是电子书朗读器中&…...

小公司做自动化的困境

1. 人员数量不够 非常常见的场景, 开发没几个, 凭什么测试要那么多, 假设这里面有3个测试, 是不是得有1个人会搞框架? 是不是得有2人搞功能测试, 一个人又搞框架, 有些脚本, 真来得及吗? 2. 人员基础不够 现在有的大公司, 是这样子协作的, 也就是某模块需求谁谁测试的, 那么…...

基于pytorch框架的手写数字识别(保姆级教学)

1、前言 本文基于PyTorch框架,采用CNN卷积神经网络实现MNIST手写数字识别,不仅可以在GPU上,同时也可以在CPU上运行。方便即使只有CPU的小伙伴也可以运行该模型。本博客手把手教学,如何手写网络层(3层),以及模型训练,详细介绍各参数含义与用途。 2、模型源码解读 该模型…...

注意力机制在大语言模型中的应用

在大语言模型中&#xff0c;注意力机制&#xff08;Attention Mechanism&#xff09;用于捕获输入序列中不同标记&#xff08;token&#xff09;之间的关系和依赖性。这种机制可以动态地调整每个标记对当前处理任务的重要性&#xff0c;从而提高模型的性能。具体来说&#xff0…...

qt 实现对字体高亮处理原理

在Qt中实现对文本的字体高亮处理&#xff0c;通常涉及到使用QTextDocument、QTextCharFormat和QSyntaxHighlighter。下面是一个简单的例子&#xff0c;演示如何为一个文本编辑器&#xff08;假设是QTextEdit&#xff09;添加简单的关键词高亮功能&#xff1a; 步骤 1: 定义关键…...

SAP中通过财务科目确定分析功能来定位解决BILLING问题实例

接用户反馈&#xff0c;一笔销售订单做发货后做销售发票时&#xff0c;没有成功过账到财务&#xff0c;提示财户确定错误。 这个之前可以通过VF02中点击小绿旗来重新执行过财动作&#xff0c;看看有没有相应日志来定位问题。本次尝试用此方法&#xff0c;也没有找到相关线索。 …...

充电站,正在杀死加油站

最近&#xff0c;深圳公布了一组数据&#xff0c;深圳的超级充电站数量已超过传统加油站数量&#xff0c;充电枪数量也已超过加油枪数量。 从全国范围看&#xff0c;加油站关停的速度在加快。 充电站正在杀死加油站。 加油站&#xff0c;未来何去何从&#xff1f; 01. 减少 我…...

哪个牌子的超声波清洗机好?四样超卓超声波清洗机独具特色!

眼镜是许多人日常生活中必不可少的工具&#xff0c;然而&#xff0c;相信很多人都有过清洗眼镜的烦恼。传统的清洗眼镜的方法往往不够彻底&#xff0c;容易留下污渍或者划伤镜片。因此&#xff0c;超声波洗眼镜机成为了现代人清洗眼镜的新选择。超声波洗眼镜机通过利用超声波震…...

vue3中若v-model绑定的响应字段出现三级,该如何实现rules验证规则

比如以下内容&#xff1a; 配置的rules内容 const rulesref({title:[{required:true,message:"请输入标题",trigger:"blur"},{max:50,message:"最大不能超过256个字",trigger:"blur"}],Category:[{required:true,message:"请选择…...

Docker-Compose一键部署项目

Docker-Compose一键部署项目 目录 Docker-Compose一键部署项目介绍部署Django项目项目目录结构 docker-compose.ymlnginx的default.conf文件后端Dockerfile文件mysql.env一键部署DNS域名解析引起的跨域问题 介绍 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的…...

【C++】相机标定源码笔记-线激光点云处理工具类

一个线激光点云处理工具类&#xff0c;它包含了一系列的方法用于处理和分析线激光扫描得到的点云数据。提供的功能包括&#xff1a; 通过文件或直接数据设置点云。计算线激光在机器人坐标系下的精度&#xff0c;输出内点的平均距离、最大距离、最小距离、总点数和内点数。提供了…...

解决Transformer根本缺陷,所有大模型都能获得巨大改进

即使最强大的 LLM 也难以通过 token 索引来关注句子等概念&#xff0c;现在有办法了。 最近两天&#xff0c;马斯克和 LeCun 的口水战妥妥成为大家的看点。这两位 AI 圈的名人你来我往&#xff0c;在推特&#xff08;现为 X&#xff09;上相互拆对方台。 LeCun 在宣传自家最新论…...

如何排查Java应用的死锁

排查Java应用中的死锁问题是一个复杂但重要的任务&#xff0c;因为死锁会导致应用程序停止响应&#xff0c;影响用户体验和系统稳定性。以下是一些方法和步骤&#xff0c;帮助你排查Java应用中的死锁。 1. 理解死锁的概念 在计算机科学中&#xff0c;死锁是指两个或多个线程相…...

JS面试题1

1. 延迟加载JS有哪些方式&#xff1f; defer: 等html全部解析完成&#xff0c;才会执行js代码&#xff0c;顺次执行js脚本 async&#xff1a;是和html解析同步的&#xff0c;不是顺次执行js脚本&#xff08;当有很多个js时&#xff09;&#xff0c;是谁先加载完谁先执行。 <…...

Linux网络 - 再谈、详谈UDP和TCP协议

文章目录 前言预备netstatpidofcat /etc/services 一、UDP协议UDP协议端格式UDP的缓冲区基于UDP的应用层协议 二、TCP协议1.TCP协议段格式确认应答(ACK)机制三次握手疑问1 最后一次客户端发给服务端的ACK请求怎么保证服务端能够收到&#xff1f; 四次挥手疑问2 为什么挥手是四次…...

el-form重置后input无法输入问题

新增用户遇到的问题&#xff1a; 如果你没有为 formData 设置默认值&#xff0c;而只是将其初始化为空对象 {}&#xff0c;则在打开dialog时&#xff0c;正常输入&#xff0c; formdata会变成如下 但是&#xff0c;打开后&#xff0c;直接使用 resetFields 或直接清空表单&…...