时间:2023-07-19 23:36:02 | 来源:网站运营
时间:2023-07-19 23:36:02 来源:网站运营
思源笔记折腾记录-整一个全景图浏览器-简单的全景图渲染:let fs = require('fs')let path = require('path')export let vite挂件目录 = window.siyuan.config.system.workspaceDir +'/data/viteWidgets'export function 读取挂件列表(){ let 挂件列表 =[] let 路径列表= require('fs').readdirSync(vite挂件目录) 路径列表.forEach( 路径名=>{ //如果目录下有vite.config.js if(fs.existsSync(path.join(vite挂件目录,路径名,'vite.config.js'))){ 挂件列表.push({ name:路径名, path:path.join(vite挂件目录,路径名) }) } } ) return 挂件列表}
import noobApi from '../noobApi/index.js'import { 读取挂件列表 } from './util/file.js'import { 获取可用端口号 } from './util/port.js'if (window.require) { const path = require('path') const vite = require('vite') let vite服务注册表 = {} 读取挂件列表().forEach( 挂件属性 => { 创建vite服务(挂件属性.path) } ) function 创建vite服务(文件夹路径) { return new Promise(async (resolve, reject) => { let vite配置文件路径 = path.join(文件夹路径, 'vite.config.js') if (!vite服务注册表.文件夹路径) { let server = await vite.createServer({ configFile: vite配置文件路径, root: 文件夹路径, }) !vite服务注册表[文件夹路径]?vite服务注册表[文件夹路径]={}:null vite服务注册表[文件夹路径]['server'] = server let port if (server.config.server.port) { port = await 获取可用端口号(server.config.server.port) } else { port =await 获取可用端口号(6806) } await server.listen(port,'127.0.0.1').then( s => { console.log(文件夹路径,'的开发服务在:',port,'上启用') vite服务注册表[文件夹路径]['port'] = port } ) resolve(server) } }) }}
获取可用端口号的实现其实就是尝试能不能监听这个端口,如果不能就试个新的:export async function 获取可用端口号(端口号){ return new Promise((resolve, reject) => { let http = require('http') let 测试服务 = http.createServer() let 可用端口号 = 端口号||3000 测试服务.on( 'listening',()=>{ console.log(端口号) 测试服务.close(()=>{ resolve(可用端口号) }) } ) 测试服务.on( 'error',async(error)=>{ console.log(error) if(error.code==='EADDRINUSE'){ resolve(await 获取可用端口号(可用端口号+1)) } else{ reject(error) } } ) 测试服务.listen(端口号) }) }
npm i photo sphere viewer --registry=https://registry.npmmirror.com
import { Viewer } from 'photo-sphere-viewer';//这里是引入了css,vite里面你这么干跟在html里面引入差不多import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'const viewer = new Viewer({ container: document.querySelector('#viewer'), //这个是我之前上传到工作空间里的一张全景图 panorama: 'assets/11111D5_全景图 1_20221211_061304-20221211182953-7i0dt0q.jpg',});
就像这样:PhotoSphereViewer.GalleryPlugin
这里我们约定文件名为:全景图-<项目名>-<空间名>-<id>.jpg的附件文件就是某一个系列的全景图。select * from assetswhere name like '全景图-${项目名}-%'
然后我们来实验一下:import { Viewer } from 'photo-sphere-viewer';import {GalleryPlugin} from 'photo-sphere-viewer/dist/plugins/gallery.js'import 核心api from 'http://127.0.0.1:6806/snippets/noobApi/util/kernelApi.js'import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'import 'photo-sphere-viewer/dist/plugins/gallery.css'import { 获取地址参数 } from '../../whiteBoard/src/data';let {project} =获取地址参数()console.log(project)let sql =`select * from assets where name like '全景图-${project}-%'`let 全景图列表 = await 核心api.sql({stmt:sql})console.log(全景图列表)全景图列表.forEach( item=>{ item.panorama=item.path item.thumbnail =item.path let 空间名 = item.name.split('-')[2] item.options ={ caption: 空间名, } })console.log(Viewer,GalleryPlugin)const viewer = new Viewer({ container: document.querySelector('#viewer'), panorama: 全景图列表[0].path, plugins: [ [GalleryPlugin, { visibleOnLoad: true, }], ],});const gallery = viewer.getPlugin(GalleryPlugin);gallery.setItems(全景图列表)
function 创建vite服务(文件夹路径) { return new Promise(async (resolve, reject) => { let vite配置文件路径 = path.join(文件夹路径, 'vite.config.js') if (!vite服务注册表.文件夹路径) { let vite中间件 = await vite.createServer({ configFile: vite配置文件路径, root: 文件夹路径, server: { middlewareMode: "html" } }) const app = express() !vite服务注册表[文件夹路径] ? vite服务注册表[文件夹路径] = {} : null vite服务注册表[文件夹路径]['server'] = app let port = vite中间件.config.server.port || 6807 port = await 获取可用端口号(port) let server = await app.listen(port, '127.0.0.1', async () => { vite服务注册表[文件夹路径]['port'] = port vite服务注册表[文件夹路径]['server'] = server vite服务注册表[文件夹路径]['app'] = app vite服务注册表[文件夹路径]['vite'] = vite中间件 console.log(文件夹路径, '的开发服务在:', 'http://127.0.0.1:' + port, '上启用') if (require('fs').existsSync(文件夹路径 + '/backend/index.js')) { //因为某些蛋疼的原因,这里只能用require let router = require(文件夹路径 +'/backend/index.js') //主意router不要妨碍vite的工作,也就是别占了vite的坑 app.use(router) app.use(vite中间件.middlewares) } })/*.then( s => { let {address,port} = server.httpServer.address() console.log(文件夹路径,'的开发服务在:','http://'+address+':'+port,'上启用') vite服务注册表[文件夹路径]['port'] = port console.log(server) } )*/ resolve(server) } }) }
这样之后,随便试一下,就把文件存在data/widgetsData里面吧。const express = require('express')let router = express.Router()const fs = require('fs')const path = require('path')let 数据路径 = path.join(window.siyuan.config.system.workspaceDir,'data','widgetsData','sphereViewer')if(fs.existsSync(数据路径)){ //为了避免跟思源的接口重合,挂件后端的接口全都加上widget前缀好了 router.use('/widgetData',express.static(数据路径)) router.use('/widgetApi/projects/getAll',(req,res)=>{ res.json(fs.readdirSync(数据路径) })}//上面已经做了自动导入,回自动把这个接口混入vite的开发服务器当中module.exports=router
这样之后,往这个文件夹里面放一点文件:import { 核心api } from "../../../whiteBoard/src/data"export class sql全景图适配器{ 获取项目列表(){ } async 获取全景图列表(项目名){ let sql =`select * from assets where name like '全景图-${项目名}-%'` let 全景图列表 = await 核心api.sql({stmt:sql}) 全景图列表.forEach( item=>{ item.panorama=item.path item.thumbnail =item.path let 空间名 = item.name.split('-')[2] item.options ={ caption: 空间名, } } ) return 全景图列表 }}import { Viewer } from 'photo-sphere-viewer';import {GalleryPlugin} from 'photo-sphere-viewer/dist/plugins/gallery.js'import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'import 'photo-sphere-viewer/dist/plugins/gallery.css'import { 获取地址参数 } from '../../whiteBoard/src/data';import {sql全景图适配器} from "./adapters/sql.js"let {project} =获取地址参数()console.log(project)let 当前适配器 = new sql全景图适配器()let 全景图列表= await 当前适配器.获取全景图列表(project) const viewer = new Viewer({ container: document.querySelector('#viewer'), panorama: 全景图列表[0].path, plugins: [ [GalleryPlugin, { visibleOnLoad: true, }], ],});const gallery = viewer.getPlugin(GalleryPlugin);gallery.setItems(全景图列表)
这个时候访问127.0.0.1:6809/?project=云park,应该可以看到跟之前一样的结果。export class sql全景图适配器{ 获取项目列表(){ } async 获取全景图列表(项目名){ let res = await fetch('widgetApi/projects/getScenesByName',{ method:"POST", body:{ name:项目名 } }) let 全景图列表 = await res.json() return 全景图列表 }}
router.post('widgetApi/projects/getScenesByName',(req,res)=>{ let {name} = req.body let 场景列表 = [] let 项目文件列表 = fs.readdirSync(path.join(数据路径,name)) 项目文件列表.forEach( 路径名=>{ let 缩略图路径 if( fs.existsSync(path.join(数据路径,name,路径名,'thumbnail.jpg'))){ 缩略图路径 = path.join('/widgetData',name,路径名,'thumbnail.jpg').replace(////g,'/') }else if( fs.existsSync(path.join(数据路径,name,路径名,'_f.jpg')) ){ 缩略图路径=path.join('/widgetData',name,路径名,'_f.jpg').replace(////g,'/') }else if( fs.existsSync(path.join(数据路径,name,路径名,'sphere.jpg')) ){ 缩略图路径=path.join('/widgetData',name,路径名,'sphere.jpg').replace(////g,'/') } if(fs.existsSync(path.join(数据路径,name,路径名,'_b.jpg'))){ 场景列表.push( { id:路径名, panorama:{ left: path.join('/widgetData',name,路径名,'_r.jpg').replace(////g,'/'), front: path.join('/widgetData',name,路径名,'_b.jpg').replace(////g,'/'), right: path.join('/widgetData',name,路径名,'_l.jpg').replace(////g,'/'), back: path.join('/widgetData',name,路径名,'_f.jpg').replace(////g,'/'), top: path.join('/widgetData',name,路径名,'_u.jpg').replace(////g,'/'), bottom: path.join('/widgetData',name,路径名,'_d.jpg').replace(////g,'/'), }, thumbnail:缩略图路径, options:{ caption:name, } } ) } else if(fs.existsSync(path.join(数据路径,name,路径名,'sphere.jpg'))){ 场景列表.push( { id:路径名, panorama:path.join('/widgetData',name,路径名,'sphere.jpg').replace(////g,'/'), options:{ caption:name, }, thumbnail:缩略图路径, } ) } } ) res.json(场景列表) })
看起来应该跟上面的这个差不多对吧,就是识别文件夹里的文件,然后匹配下路径然后返回。panorama:{ left: path.join('/widgetData',name,路径名,'_r.jpg').replace(////g,'/'), front: path.join('/widgetData',name,路径名,'_b.jpg').replace(////g,'/'), right: path.join('/widgetData',name,路径名,'_l.jpg').replace(////g,'/'), back: path.join('/widgetData',name,路径名,'_f.jpg').replace(////g,'/'), top: path.join('/widgetData',name,路径名,'_u.jpg').replace(////g,'/'), bottom: path.join('/widgetData',name,路径名,'_d.jpg').replace(////g,'/'),},
因为渲染器给出的六面全景图一般是按照“人在方盒子里面”来适配六个面的,而PhotoSphereViewer是按照“人在方盒子外面”来读取的,所以读取文件的时候,除了上下不用反之外,其他前后左右都要反一下~~~import {后端适配器} from './adapters/internal.js'let {project} =获取地址参数()console.log(project)let 当前适配器 = new 后端适配器()let 全景图列表= await 当前适配器.获取全景图列表(project) const viewer = new Viewer({ container: document.querySelector('#viewer'), panorama: 全景图列表[0].path, plugins: [ [GalleryPlugin, { visibleOnLoad: true, }], ],});const gallery = viewer.getPlugin(GalleryPlugin);gallery.setItems(全景图列表)
然后它就报错了:const bodyParser = require('body-parser')router.post('/widgetApi/projects/getScenesByName', (req,res,next)=>{ //强制按json解析,这样前端就不用设置content-type了 req.headers['content-type']='application/json' //记得调用next() next() }, bodyParser.json(), let {name} = req.body let 场景列表 = [] let 项目文件列表 = fs.readdirSync(path.join(数据路径,name)) 项目文件列表.forEach( 路径名=>{ let 缩略图路径 if( fs.existsSync(path.join(数据路径,name,路径名,'thumbnail.jpg'))){ 缩略图路径 = path.join('/widgetData',name,路径名,'thumbnail.jpg').replace(////g,'/') }else if( fs.existsSync(path.join(数据路径,name,路径名,'_f.jpg')) ){ 缩略图路径=path.join('/widgetData',name,路径名,'_f.jpg').replace(////g,'/') }else if( fs.existsSync(path.join(数据路径,name,路径名,'sphere.jpg')) ){ 缩略图路径=path.join('/widgetData',name,路径名,'sphere.jpg').replace(////g,'/') } if(fs.existsSync(path.join(数据路径,name,路径名,'_b.jpg'))){ 场景列表.push( { id:路径名, panorama:{ left: path.join('/widgetData',name,路径名,'_r.jpg').replace(////g,'/'), front: path.join('/widgetData',name,路径名,'_b.jpg').replace(////g,'/'), right: path.join('/widgetData',name,路径名,'_l.jpg').replace(////g,'/'), back: path.join('/widgetData',name,路径名,'_f.jpg').replace(////g,'/'), top: path.join('/widgetData',name,路径名,'_u.jpg').replace(////g,'/'), bottom: path.join('/widgetData',name,路径名,'_d.jpg').replace(////g,'/'), }, thumbnail:缩略图路径, options:{ caption:name, } } ) } else if(fs.existsSync(path.join(数据路径,name,路径名,'sphere.jpg'))){ 场景列表.push( { id:路径名, panorama:path.join('/widgetData',name,路径名,'sphere.jpg').replace(////g,'/'), options:{ caption:name, }, thumbnail:缩略图路径, } ) } } ) res.json(场景列表)}
然后再看一下127.0.0.1:6809/?project=云park48let 全景图选项 = { container: document.querySelector('#viewer'), panorama: 全景图列表[0].panorama, plugins: [ [GalleryPlugin, { visibleOnLoad: true, }], ],}//如果有六面图文件,就使用六面图适配器if(全景图列表[0].panorama.left){ 全景图选项.adapter = CubemapAdapter}let viewer= new Viewer(全景图选项)
这回显示对了,效果就像这样:关键词:浏览,简单,渲染,笔记,折腾,记录